云原生之深入解析docker实用工具gosu和su-exec实践

一、volume 的权限问题

  • 在 Docker 中,需要把 host 的目录挂载到 container 中作为 volume 使用时,往往会发生文件权限问题。常见的现象是,container 对该路径并无写权限,以致其中服务的各种千奇百怪的问题。
  • 导致这类问题的原因,是 container 内外的 UID 不同。比如,host 当前使用 docker 的用户 UID 是 1000(这是默认第一个用户的 UID),如果 container 内的 UID 是 2000,那么 host 创建的目录对 container 来说就并非 owner,默认情况下不可写入。
  • 此外还有一种情况,那就是挂载前,host 上不存在被挂载的目录。Docker 会以 root 权限,先创建该目录,再挂载。这就导致,即使 host 与 container 的 UID 都是 1000,也会出现无写权限的情况。这种现象,只会在初始化时出现,但也足够令新手困惑,令老手厌烦。
  • 为什么在 Dockerfile 中不能把 volume 的权限配置好?因为 Dockerfile 是对 image 的描述,而 volume 则是 container 的内容。Dockerfile 中做出的权限配置,对非 volume 来说是可以生效的,而对 volume 则不然。本质上,host 挂载到 volume 上的目录,是属于 host 的。Dockerfile 是在docker build期间执行,而 volume 则是在docker run的时候产生。
  • 其实,Docker 在自动创建 volume 路径时,应该再自动地把它修改为 container 内前台进程的 user:group。然而 Docker 目前并无此类机制,俺们这些用户就只能另谋出路。
  • 一般的临时方案,都是去手动修改权限。要么通过 chown,把 owner 改成 container 内用户的 UID;要么通过 chmod 777,搞成所有用户通用。这些当然不是什么好的长期方案,也违背了 Docker 方便部署的初衷。
  • 目前看来,最好的方案,还是定制 Dockerfile 的 ENTRYPOINT。

二、ENTRYPOINT

  • ENTRYPOINT 有以下几个重点:
    • ENTRYPOINT 指定镜像的默认入口命令,该入口命令会在启动容器时作为根命令执行,所有其他传入值作为该命令的参数。
    • ENTRYPOINT 的值可以通过 docker run --entrypoint 来覆盖掉。
    • 只有 Dockerfile 中的最后一条 ENTRYPOINT 指令会起作用。
  • 当指定了 ENTRYPOINT 后,CMD 的含义就发生了改变,不再是直接的运行其命令,而是将 CMD 的内容作为参数传给 ENTRYPOINT 指令。换句话说实际执行时,会变成 “”。
  • 因此在 dockerfile 中 ENTRYPOINT 里编写一个入口脚本 entrypoint.sh 或 docker-entrypoint.sh。在容器运行的时候通过 ENTRYPOINT 来做一些操作,比如把 volume 挂载的目录权限给改正确,然后再切换普通用户运行正常的程序进程。

三、gosu 和 su-exec

  • gosu 的 github 仓库地址:
https://github.com/tianon/gosu
  • 用法:
$ gosu
Usage: ./gosu user-spec command [args]eg: ./gosu tianon bash./gosu nobody:root bash -c 'whoami && id'./gosu 1000:1 id./gosu version: 1.1 (go1.3.1 on linux/amd64; gc)
  • 简单例子:
$ docker run -it --rm ubuntu:trusty su -c 'exec ps aux'
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.0  46636  2688 ?        Ss+  02:22   0:00 su -c exec ps a
root         6  0.0  0.0  15576  2220 ?        Rs   02:22   0:00 ps aux
$ 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
$ 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
  • 不管是su还是sudo,他们在执行ps aux命令的 PID 编号都不为 1。在容器中虽然可以,但是这不是一个好的方案,容器里面 PID=1 的进程就是应用本身。因此可以使用 gosu 命令来切换用户执行命令。
  • 对于 debian 安装方法如下:
    • Debian 9(“Debian Stretch”)或更新的版本:
RUN set -eux; \apt-get update; \apt-get install -y gosu; \rm -rf /var/lib/apt/lists/*; \
# verify that the binary worksgosu nobody true
    • 较旧的 Debian 版本(或较新的 gosu 版本):
ENV GOSU_VERSION 1.16
RUN set -eux; \
# save list of currently installed packages for later so we can clean upsavedAptMark="$(apt-mark showmanual)"; \apt-get update; \apt-get install -y --no-install-recommends ca-certificates wget; \if ! command -v gpg; then \apt-get install -y --no-install-recommends gnupg2 dirmngr; \elif gpg --version | grep -q '^gpg (GnuPG) 1\.'; then \
# "This package provides support for HKPS keyservers." (GnuPG 1.x only)apt-get install -y --no-install-recommends gnupg-curl; \fi; \rm -rf /var/lib/apt/lists/*; \\dpkgArch="$(dpkg --print-architecture | awk -F- '{ print $NF }')"; \wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch"; \wget -O /usr/local/bin/gosu.asc "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch.asc"; \\
# verify the signatureexport GNUPGHOME="$(mktemp -d)"; \gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4; \gpg --batch --verify /usr/local/bin/gosu.asc /usr/local/bin/gosu; \command -v gpgconf && gpgconf --kill all || :; \rm -rf "$GNUPGHOME" /usr/local/bin/gosu.asc; \\
# clean up fetch dependenciesapt-mark auto '.*' > /dev/null; \[ -z "$savedAptMark" ] || apt-mark manual $savedAptMark; \apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false; \\chmod +x /usr/local/bin/gosu; \
# verify that the binary worksgosu --version; \gosu nobody true
    • 对于 alpine (3.7+):当使用 Alpine 时,可能也值得检查一下su-exec(apk add --no-cache su-exec),自从 0.2 版以来,它完全与gosu兼容,文件大小只有几分之一:
ENV GOSU_VERSION 1.16
RUN set -eux; \\apk add --no-cache --virtual .gosu-deps \ca-certificates \dpkg \gnupg \; \\dpkgArch="$(dpkg --print-architecture | awk -F- '{ print $NF }')"; \wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch"; \wget -O /usr/local/bin/gosu.asc "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch.asc"; \\
# verify the signatureexport GNUPGHOME="$(mktemp -d)"; \gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4; \gpg --batch --verify /usr/local/bin/gosu.asc /usr/local/bin/gosu; \command -v gpgconf && gpgconf --kill all || :; \rm -rf "$GNUPGHOME" /usr/local/bin/gosu.asc; \\
# clean up fetch dependenciesapk del --no-network .gosu-deps; \\chmod +x /usr/local/bin/gosu; \
# verify that the binary worksgosu --version; \gosu nobody true

四、entrypoint 脚本文件

  • 脚本例 1:
#!/bin/sh
set -e
ls ${LOG_PATH} > /dev/null 2>&1 || mkdir -p ${LOG_PATH}
chown -R www-data ${LOG_PATH}
if [ $# -gt 0 ];then#su ${USERNAME} -c "exec $@"exec su-exec www-data $@
else#su ${USERNAME} -c "exec uwsgi --ini uwsgi.ini --http=0.0.0.0:${DJANGO_PORT}"exec su-exec www-data uwsgi --ini uwsgi.ini --http=0.0.0.0:${DJANGO_PORT}
fi
  • 脚本说明:
    • set -e:如果出现命令执行失败,那么就应该退出脚本不继续往下执行,避免失败对后续有影响。可以避免操作失败还继续往下执行的问题。
    • exec:系统调用exec是以新的进程去代替原来的进程,但进程的 PID 保持不变,可以保证容器的主程序 PID=1。
  • 脚本例 2:
#!/bin/sh
set -e
if [ "$1" = 'uwsgi' -a "$(id -u)" = '0' ]
thenls ${LOG_PATH} > /dev/null 2>&1 || mkdir -p ${LOG_PATH}chown -R www-data ${LOG_PATH}exec su-exec www-data "$0" "$@"
fi
exec "$@"
  • 脚本说明:
    • 当前用户是 root 的话, 那么创建和修改 LOG_PATH 目录权限,并切换到 www-data 的身份,带上剩余的参数,再次运行 docker-entrypoint.sh 文件(" 0 " 表示 d o c k e r − e n t r y p o i n t . s h 本身, " 0"表示 docker-entrypoint.sh 本身," 0"表示dockerentrypoint.sh本身,"@"表示剩余的参数)。如果此脚本其他位置还有需要由 www-data 用户执行的代码,则可以一并执行。
    • 当再次执行该脚本时由于已经不是 root 用户了, 会直接执行exec “$@”, 于是直接执行带的参数,即 CMD 定义的脚本。
  • 在 Dockerfile 中添加 docker-entrypoint.sh 脚本,并且需要注意x执行权限,否则将无权限执行:
COPY docker-entrypoint.sh /usr/local/bin/
ENTRYPOINT ["docker-entrypoint.sh"]
  • 通过此 docker-entrypoint.sh 脚本,可以在容器运行时强制把目录权限修改成需要的权限,即使 docker 通过 root 用户初始化创建的 volume 挂载目录。如此一来,就可以通过容器中的普通用户来运行程序,并在这个普通的权限的目录中写入文件。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/224763.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

maven jar sort

1)往常项目结构lib包排序 2)maven的默认是没有排序的

《数据结构、算法与应用C++语言描述》- 构建哈夫曼树

哈夫曼树 完整可编译运行代码见:Github::Data-Structures-Algorithms-and-Applications/_29huffmanTree 定长编码与可变长编码 定长编码 每个字符都用固定长度的编码来表示。 例如假设一个文本是由字符 a、u、x 和 z 组成的字符串,每个字符用2位二进…

Python录制和绘制音频

要使用Python录制和绘制音频,使用Python的音频处理库和绘图库。 以下是一个简单的示例代码,演示如何使用Python录制音频并绘制其波形: import wave import numpy as np import matplotlib.pyplot as plt# 设置音频参数 sample_rate = 44100 # 采样率 duration = 5 # 录制…

【idea】idea尾部自动删除空格,idea2023.1.2关闭自动去除行尾空格的功能

这个功能是由于git或者svn上的代码有许多空格的时候,会自动把空格去掉,就会导致出现许多更改的地方,会自动删空格。 尾部刚打好空格准备写代码,自动就删掉空格,又得重打空格后继续编码,非常不爽。 设置如…

HTML5 Canvas画布讲解

一、canvas 简介 ​<canvas> 是 HTML5 新增的&#xff0c;一个可以使用脚本(通常为 JavaScript) 在其中绘制图像的 HTML 元素。它可以用来制作照片集或者制作简单(也不是那么简单)的动画&#xff0c;甚至可以进行实时视频处理和渲染。 ​它最初由苹果内部使用自己 MacO…

我的NPI项目之Android 安全系列 -- EMVCo

最近一直在和支付有关的内容纠缠&#xff0c;原来我负责的产品后面还要过EMVCo的认证。于是&#xff0c;就网上到处找找啥事EMVCo&#xff0c;啥是EMVCo&#xff0c;啥是EMVCo。 于是找到了一个神奇的个人网站&#xff1a;Ganeshji Marwaha 虽然时间有点久远&#xff0c;但是用…

黑马点评04集群下的并发安全

实战篇-08.优惠券秒杀-集群下的线程并发安全问题_哔哩哔哩_bilibili 为了应对高并发&#xff0c;需要把项目部署到多个机器构成集群&#xff0c;所以需要配置nginx。 1.如何模拟集群 通过idea的ctrl d修改配置&#xff0c;实现多个tomcat运行模拟集群 然后在nginx上配置节点&…

如何在PHP中使用Memcached和Redis?

在 PHP 中使用 Memcached 和 Redis 主要涉及两个方面&#xff1a;安装相关扩展和编写代码进行交互。以下是在 PHP 中使用 Memcached 和 Redis 的基本步骤&#xff1a; 使用 Memcached&#xff1a; 1. 安装 Memcached 扩展&#xff1a; 确保你的系统上安装了 Memcached 服务器…

计算机网络快速刷题

自用//奈奎斯特定理和香农定理计算题 参考博客&#xff1a;UDP协议是什么&#xff1f;作用是什么&#xff1f; 肝了&#xff0c;整理了8张图详解ARP原理 【网络协议详解】——FTP系统协议&#xff08;学习笔记&#xff09; 在OSI参考模型中&am…

Tekton 克隆 git 仓库

Tekton 克隆 git仓库 介绍如何使用 Tektonhub 官方 git-clone task 克隆 github 上的源码到本地。 git-clone task yaml文件下载地址&#xff1a;https://hub.tekton.dev/tekton/task/git-clone 查看git-clone task yaml内容&#xff1a; 点击Install&#xff0c;选择一种…

聊聊Java中的常用类String

String、StringBuffer、StringBuilder 的区别 从可变性分析 String不可变。StringBuffer、StringBuilder都继承自AbstractStringBuilder &#xff0c;两者的底层的数组value并没有使用private和final修饰&#xff0c;所以是可变的。 AbstractStringBuilder 源码如下所示 ab…

最新AI绘画Midjourney绘画提示词Prompt教程

一、Midjourney绘画工具 SparkAi【无需魔法使用】&#xff1a; sparkAi创作系统是基于ChatGPT进行开发的Ai智能问答系统和Midjourney绘画系统&#xff0c;支持OpenAI-GPT全模型国内AI全模型。本期针对源码系统整体测试下来非常完美&#xff0c;可以说SparkAi是目前国内一款的…

《Kotlin核心编程》笔记:可空类型平台类型装箱类型数组类型泛型协变与逆变

可空类型 在Kotlin中&#xff0c;我们可以在任何类型后面加上“?”&#xff0c;比如“Int?”&#xff0c;实际上等同于“Int? Int or null”。 通过合理的使用&#xff0c;不仅能够简化很多判空代码&#xff0c;还能够有效避免空指针异常。 注意&#xff1a;由于null只能…

Tomcat 十大安全优化方法(详解版)

目录 1 talnet管理端口保护 2 AJP连接端口保护 3 禁用管理器 4 降权启动 5 控制文件列表的访问 6 隐藏版本信息 7 server header重写 8 限制IP访问 9 修改脚本权限 10 访问日志格式规范 1 talnet管理端口保护 配置内容&#xff1a; &#xff08;1&#xff09;修改默…

HCIA-H12-811题目解析(3)

1、【单选题】 以下关于路由器的描述&#xff0c;说法错误的是&#xff1f; 2、【单选题】某网络工程师在输入命令行时提示如下信息&#xff1a;Error:Unrecognized command foun at position.对于该提示信息说法正确的是&#xff1f; 3、【单选题】如下图所示的网络&#xf…

【Axure RP9】的详细安装及Axure入门应用

目录 一 Axure入门安装 1.1 Axure是什么? 1.2 Axure应用场景 1.3 Axure安装 1.3.1 汉化 1.3.2 授权 二, Axure应用 1.1 Axure软件界面概述 1.2 Axure的应用 1.2.1备份 1.2.2 视图显示及网格设置 1.2.3 生成HTML文件 1.2.4 备注说明 一 Axure入门安装 1.1 Axure…

搭建你的知识付费小程序平台:源码解析与技术实现

知识付费小程序平台在当今数字化时代扮演着越来越重要的角色&#xff0c;为教育者和学习者提供了一个灵活、便捷的学习环境。本文将以关键词“知识付费小程序源码”为基础&#xff0c;探讨如何搭建一个功能强大的知识付费小程序平台&#xff0c;并提供一些基础的技术代码示例。…

vue与angular以及react的区别

Vue、Angular和React都是流行的前端框架&#xff0c;它们各自有一些显著的区别。 Vue 简洁易学&#xff1a;Vue被广泛认为是最容易学习和上手的前端框架之一&#xff0c;因为它的核心库相对小巧且易于理解。渐进式框架&#xff1a;Vue被设计成逐步增强的框架&#xff0c;可以…

Elasticsearch的 8.x常用api汇总

ES的查询语法比较复杂,对于初学者需要在不断练习中才会逐渐掌握,本文汇总了ES各种查询语法以及常用api,可以作为新手的实用笔记 首先,安装 Kibana! 下载Elasticsearch,官方下载页面;Elasticsearch 参考,官方文档;<

湖南财信:灰盒测试筑牢安全防线,保障差异化金融服务体系建设

湖南财信是国有独资公司&#xff0c;湖南省唯一的省级地方金融控股公司、省属国有大型骨干企业。湖南财信坚持金融科技战略&#xff0c;以数字化建设为驱动&#xff0c;创新融资服务手段&#xff0c;逐步打造出差异化产品与数字化服务体系&#xff0c;全方位、多维度推动金融服…