0
点赞
收藏
分享

微信扫一扫

Docker系列之Dockerfile详解EXPOSE|WORKDIR|USER(七)

Docker系列之Dockerfile详解EXPOSE|WORKDIR|USER(七)_redis

EXPOSE 声明端口

1、格式

  • ​EXPOSE <端口1> [<端口2>...]​

2、作用

​EXPOSE​​ 指令是声明运行时容器提供服务端口,这只是一个声明,在运行时并不会因为这个声明应用就会开启这个端口的服务。在 Dockerfile 中写入这样的声明有两个好处:

  • 一个是帮助镜像使用者理解这个镜像服务的守护端口,以方便配置映射;
  • 另一个用处则是在运行时使用随机端口映射时,也就是​​docker run -P​​ 时,会自动随机映射​​EXPOSE​​ 的端口。

要将 ​​EXPOSE​​ 和在运行时使用 ​​-p <宿主端口>:<容器端口>​​ 区分开来。

  • ​-p​​,是映射宿主端口和容器端口,换句话说,就是将容器的对应端口服务公开给外界访问,
  • ​EXPOSE​​ 仅仅是声明容器打算使用什么端口而已,并不会自动在宿主进行端口映射。

WORKDIR 指定工作目录

1、格式

  • ​WORKDIR <工作目录路径>​

2、作用

使用 ​​WORKDIR​​ 指令可以来指定工作目录(或者称为当前目录),以后各层的当前目录就被改为指定的目录,如该目录不存在,​​WORKDIR​​ 会帮你建立目录。

之前提到常见的错误是把 ​​Dockerfile​​ 等同于 Shell 脚本来书写,这种错误的理解还可能会导致出现下面这样的错误:

RUN cd /app
RUN echo "hello" > world.txt
复制代码

如果将这个 ​​Dockerfile​​ 进行构建镜像运行后,会发现找不到 ​​/app/world.txt​​ 文件,或者其内容不是 ​​hello​​。原因其实很简单,在 Shell 中,连续两行是同一个进程执行环境,因此前一个命令修改的内存状态,会直接影响后一个命令;而在 ​​Dockerfile​​ 中,这两行 ​​RUN​​ 命令的执行环境根本不同,是两个完全不同的容器。这就是对 ​​Dockerfile​​ 构建分层存储的概念不了解所导致的错误。

之前说过每一个 ​​RUN​​ 都是启动一个容器、执行命令、然后提交存储层文件变更。第一层 ​​RUN cd /app​​ 的执行仅仅是当前进程的工作目录变更,一个内存上的变化而已,其结果不会造成任何文件变更。而到第二层的时候,启动的是一个全新的容器,跟第一层的容器更完全没关系,自然不可能继承前一层构建过程中的内存变化。

因此如果需要改变以后各层的工作目录的位置,那么应该使用 ​​WORKDIR​​ 指令。

USER 指定当前用户

1、格式

  • ​USER <用户名>[:<用户组>]​

2、作用

​USER​​ 指令和 ​​WORKDIR​​ 相似,都是改变环境状态并影响以后的层。

  • ​WORKDIR​​ 是改变工作目录
  • ​USER​​ 是改变之后层的执行​​RUN​​,​​CMD​​ 以及​​ENTRYPOINT​​ 这类命令的身份。

当然,和 ​​WORKDIR​​ 一样,​​USER​​ 只是帮助你切换到指定用户而已,这个用户必须是事先建立好的,否则无法切换。

RUN groupadd -r redis && useradd -r -g redis redis
USER redis
RUN [ "redis-server" ]
复制代码

如果以 ​​root​​ 执行的脚本,在执行期间希望改变身份,比如希望以某个已经建立好的用户来运行某个服务进程,不要使用 ​​su​​ 或者 ​​sudo​​,这些都需要比较麻烦的配置,而且在 TTY 缺失的环境下经常出错。建议使用 ​​​gosu​​​。

# 建立 redis 用户,并使用 gosu 换另一个用户执行命令
RUN groupadd -r redis && useradd -r -g redis redis
# 下载 gosu
RUN wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/1.7/gosu-amd64" \
&& chmod +x /usr/local/bin/gosu \
&& gosu nobody true
# 设置 CMD,并以另外的用户执行
CMD [ "exec", "gosu", "redis", "redis-server" ]
举报

相关推荐

0 条评论