Posted on:
Last modified:
Dockerfile 列出了构建一个 docker image 的可复现步骤。比起一步一步通过 docker commit 来制作一个镜像,dockerfile 更适用于 CI 自动测试等系统。
sh -c
大部分命令都是可以「望文生义」的,只有个别几个比较让人迷惑。
ADD 命令比较复杂,支持 tar 包和网络等复杂行为,一般用不到。
COPY 命令和 Linux 上的 cp 命令的行为是不同的。COPY 命令会自动创建文件路径。另外,COPY
只能从当前目录复制,而不能使用 ../
这些父级目录,因为只有当前目录作为构建上下文传递给了
docker daemon。
另外,COPY
的行为在各种情况下都很一致,而 cp
则比较混乱。
如果目标文件夹存在,Linux 上的 cp
有时会把源文件夹复制到目标文件夹中成为子目录,有时又会
复制源文件夹的内容,非常让人迷惑。更糟的是,macOS 上的 cp
行为也和 Linux 上有差异。
COPY 命令始终会复制源文件夹的内容到目标文件夹中。具体来说:
cp -R foo/ bar/
, 会产生 bar/foo
这种目录。想要复制内容需要使用 cp -R foo/* bar/
cp -R foo/ bar/
,只会复制内容。cp -R . /app
, 只会复制当前目录的内容COPY foo/ bar/
, COPY . /app
都是针对内容,行为一致。可以看出 COPY
命令本身是很简单且一致的,但是我们可能会被头脑中混乱的 cp
影响而产生困惑。
ENTRYPOINT 指定了 Docker 镜像要运行的二进制文件(当然也包括参数),而 CMD 则指定了运行
这个二进制文件的参数。不过因为默认 entrypoint 是 sh -c
,所以实际上 CMD 才是运行的命令。
另外,如果 docker run 中包含命令行参数,会替换掉 CMD 的内容。如果使用 /bin/bash 作为 docker run 的参数,便可以进入容器中的 Shell,并查看编译出的文件系统究竟是什么样的。
个人倾向于只使用 CMD,而不使用 ENTRYPOINT。
Dockerfile 中的 volume 指定了一个匿名的 docker volume,也就是说在 docker run 的时候,docker
会把对应的目录 mount 到一个匿名的卷。当然如果使用 -v
参数指定了 mount 到哪个目录,或者
是指定了卷名,那就不会采用匿名的卷了。
首先是指令的排序,我们都知道 FROM
一般放在最前边,那么其他指令怎么排序呢?这里有几条规则:
FROM ubuntu
WORKDIR /opt
EXPOSE 3000
VOLUME ["/data"]
ENTRYPOINT ["node"]
CMD ["server.js"]
COPY package.json /opt/package.json
RUN apt-get update && \
apt-get install curl && \
npm install --production
COPY . /opt
ARG BUILD_REVISION=master
ENV REVISION=${BUILD_REVISION}
对于需要编译的项目,实际上我们只需把编译后的文件复制到 docker 镜像中即可,而不需要把编译 使用的所有依赖都放进去。这时候可以使用多阶段构建,也就是把 docker build 分为编译和生产两个 阶段。
这里的关键在于使用 FROM AS
和 COPY --from
两个命令。以前端项目为例,我们使用 node 镜像
编译出
# Compile
FROM node AS builder
WORKDIR /build
COPY package.json package-lock.json ./
RUN npm install
COPY . /build
RUN npm run build
# Put content into nginx
FROM nginx
WORKDIR /app
COPY nginx.conf /etc/nginx/nginx.conf
COPY --from=builder /build/dist /usr/share/nginx/html
对于 Python 这种无需编译的语言,其实也可以借助多阶段构建来缩减镜像大小。
FROM python:3.10 as builder
WORKDIR /venv
COPY requirements.txt ./
# 注意这里的 --copies 选项,使用这个选项后,venv 会复制文件到虚拟环境中,而不是使用链接。
RUN python -m venv --copies /venv && \
. ./bin/activate && \
pip install -r requirements.txt
# 注意这里使用了 slim 镜像
FROM python:3.10-slim
ENV PATH=/venv/bin:$PATH
WORKDIR /app
COPY --from=builder /venv /venv
COPY . /app
CMD ["python", "server.py"]
在完整镜像中包含了许多构建工具,生产环境中并不需要这些工具,所以可以使用 slim 镜像。
最后需要说明的一点,不要轻易使用 alpine 镜像。虽然 alpine 体积更小,但是因为使用了 musl, 性能可能相对 glibc 编译的镜像要差不少,为了一点点磁盘空间去花费更多的 CPU 资源,一般是 不值得的。
© 2016-2022 Yifei Kong. Powered by ynotes
All contents are under the CC-BY-NC-SA license, if not otherwise specified.
Opinions expressed here are solely my own and do not express the views or opinions of my employer.
友情链接: MySQL 教程站