Docker DockerFile

Dockerfile 是一个文本文件,其内包含了一条条的 指令(Instruction),每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。

使用 Dockerfile 定制镜像

  • 创建 Dockerfile
1
2
3
mkdir test
cd test
touch Dockerfile
  • Dockerfile 写入内容
1
2
FROM nginx
RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html

这个 Dockerfile 很简单,一共就两行。涉及到了两条指令,FROMRUN

  • 构建镜像

Dockerfile 文件所在目录执行:

1
2
3
4
5
6
7
8
9
10
[root@caoxl test_nginx]# docker build -t nginx:v3 ./
Sending build context to Docker daemon 2.048kB
Step 1/2 : FROM nginx
---> 53f3fd8007f7
Step 2/2 : RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
---> Running in b4a1b636bff4
Removing intermediate container b4a1b636bff4
---> 9ab56bb5f020
Successfully built 9ab56bb5f020
Successfully tagged nginx:v3

Dockerfile 指令详解

FROM - 指定基础镜像

所谓定制镜像,那一定是以一个镜像为基础,在其上进行定制。

RUN - 执行命令

RUN 指令是用来执行命令行命令的。由于命令行的强大能力,RUN 指令在定制镜像时是最常用的指令之一。其格式有两种:

  • shell 格式RUN <命令>,就像直接在命令行中输入的命令一样。
1
RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
  • exec 格式RUN ["可执行文件", "参数1", "参数2"],这更像是函数调用中的格式
1
2
3
4
5
6
FROM debian:stretch

RUN buildDeps='gcc libc6-dev make wget' \
&& apt-get update \
&& apt-get install -y $buildDeps \
&& wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz" \

COPY - 复制文件

  • 格式
    • COPY [--chown=<user>:<group>] <源路径>... <目标路径>
    • COPY [--chown=<user>:<group>] ["<源路径1>",... "<目标路径>"]
1
COPY package.json /usr/src/app/

ADD - 更高级的复制文件

ADD 指令和 COPY 的格式和性质基本一致。但是在 COPY 基础上增加了一些功能。

1
ADD ubuntu-xenial-core-cloudimg-amd64-root.tar.gz /

Docker 官方的 Dockerfile 最佳实践文档 中要求,尽可能的使用 COPY,因为 COPY 的语义很明确,就是复制文件而已,而 ADD 则包含了更复杂的功能,其行为也不一定很清晰

CMD 容器启动命令

  • CMD 指令的格式和 RUN 相似,也是两种格式:
    • shell 格式CMD <命令>
    • exec 格式CMD ["可执行文件", "参数1", "参数2"...]

在指令格式上,一般推荐使用 exec 格式,这类格式在解析时会被解析为 JSON 数组,因此一定要使用双引号 ",而不要使用单引号。

如果使用 shell 格式的话,实际的命令会被包装为 sh -c 的参数的形式进行执行。比如:

1
CMD echo $HOME

在实际执行中,会将其变更为:

1
CMD [ "sh", "-c", "echo $HOME" ]

ENTRYPOINT - 入口点

ENTRYPOINT 的目的和 CMD 一样,都是在指定容器启动程序及参数。ENTRYPOINT 在运行时也可以替代,不过比 CMD 要略显繁琐,需要通过 docker run 的参数 --entrypoint 来指定。

1
2
3
4
5
FROM ubuntu:18.04
RUN apt-get update \
&& apt-get install -y curl \
&& rm -rf /var/lib/apt/lists/*
ENTRYPOINT [ "curl", "-s", "https://ip.cn" ]

ENV - 设置环境变量

  • 格式
    • ENV <key> <value>
    • ENV <key1>=<value1> <key2>=<value2>...
1
2
ENV VERSION=1.0 DEBUG=on \
NAME="Happy Feet"

WORKDIR - 指定工作目录

1
2
3
4
FROM node:slim
RUN mkdir /app
WORKDIR /app
CMD [ "npm", "start" ]

USER - 指定当前用户

1
2
3
RUN groupadd -r redis && useradd -r -g redis redis
USER redis
RUN [ "redis-server" ]

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

1
2
3
4
5
6
7
8
# 建立 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" ]

Dockerfile 多阶段构建

实战多阶段构建 Laravel 镜像

待更新…

参考

Powered by Hexo and Hexo-theme-hiker

Copyright © 2017 - 2021 Keep It Simple And Stupid All Rights Reserved.

访客数 : | 访问量 :