Dockerfile
文章目录
- Dockerfile
-
- 1.Layer
-
- 1.1为什引入容器镜像分层(layer)
- [1.2 镜像的内部机制是怎样的](#1.2 镜像的内部机制是怎样的)
- [1.3 镜像里的层都是只读不可修改的,但容器运行的时候经常会写入数据,这个冲突应该怎么解决呢](#1.3 镜像里的层都是只读不可修改的,但容器运行的时候经常会写入数据,这个冲突应该怎么解决呢)
- 2.Dockerfile基础
- 3.Dockerfile技巧
1.Layer
1.1为什引入容器镜像分层(layer)
- 镜像本就是是一个打包文件,但是如果只是打包一个文件我们用manifest即可,为了保证容器运行环境的一致性,镜像必须把应用程序所在操作系统的根目录,也就是 rootfs,都包含进来,虽然这些文件里不包含系统内核,但如果每个镜像都重复做这样的打包操作,仍然会导致大量的冗余,很自然的,我们就会想到,应该把重复的部分抽取出来,只存放一份根目录文件,然后让这一千个镜像以某种方式共享这部分数据
1.2 镜像的内部机制是怎样的
-
容器镜像,是由许多的镜像层组成的,每层都是只读不可修改的一组文件,相同的层可以在镜像之间共享,然后多个层像搭积木一样堆叠起来,再使用一种叫"Union FS 联合文件系统"(overlay2)的技术把它们合并在一起,就形成了容器最终看到的文件系统

1.3 镜像里的层都是只读不可修改的,但容器运行的时候经常会写入数据,这个冲突应该怎么解决呢
- docker在挂载镜像文件的时候除了镜像文件的只读层,还会挂载一个'可读写层',在容器运行是,它以copy-on-write的方式,记录容器中的'写'操作
2.Dockerfile基础
- dockerfile就是编译镜像的施工图纸
- Docker 镜像遵循的是 OCI (Open Container Initiatve) 标准,所以制作出来的镜像文件也能够被其他的容器技术 (如 Kata、Kubernetes) 识别并运行
shell
# 基础镜像
FROM python:3.10-alpine
# 镜像作者
MAINTAINER xiaopawnye
# 环境变量
ENV DJANGO_SETTINGS_MODULE=settings.local
#切换目录
WORKDIR /data/recruitment
#拷贝文件
COPY ./requirements.txt .
COPY ./start.sh .
COPY ./src .
#运行命令
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories # 替换为apk阿里云镜像
# 更新APK
RUN apk add --update --no-cache curl jq py3-configobj py3-pip py3-setuptools python3-dev \
&& apk add --no-cache gcc g++ jpeg-dev zlib-dev libc-dev libressl-dev musl-dev libffi-dev \
&& python -m pip install --upgrade pip \
&& pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple \
&& apk del gcc g++ libressl-dev musl-dev libffi-dev python3-dev \
&& apk del curl jq py3-configobj py3-pip py3-setuptools \
&& ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
&& echo 'Asia/Shanghai' >/etc/timezone \
&& rm -rf /var/cache/apk/*
RUN sed -i 's/\r//' /data/recruitment/start.sh
RUN chmod +x ./start.sh
EXPOSE 39979
CMD ["/bin/sh", "/data/recruitment/start.sh"]
shell
# 构建镜像
docker build --network=host -t xiaopawnye/recruitment-base:v1 recruitment/
# 启动镜像
docker run --rm --network=host -p 39979:39979 -v "$(pwd)":/data/recruitment --env server_params="--settings=settings.local" xiaopawnye/recruitment-base:v1
#查看构建历史
docker history <镜像名>
3.Dockerfile技巧
-
每一行的RUN命令都会产生一层image layer,容易导致镜像的臃肿,为此经常写成会将多个命令写成一条命令,末尾使用续行符 \,命令之间也会用 && 来连接
-
一条命令一旦写错了,每次调试都要重新构建也很麻烦,所以可以采用一种变通的技巧:把这些 Shell 命令集中到一个脚本文件里,用 COPY 命令拷贝进去再用 RUN 来执行
修改前
dockerfileRUN apt-get update \ && apt-get install -y \ build-essential \ curl \ make \ unzip \ && cd /tmp \ && curl -fSL xxx.tar.gz -o xxx.tar.gz\ && tar xzf xxx.tar.gz \ && cd xxx \ && ./config \ && make \ && make clean修改后
dockerfileCOPY setup.sh /tmp/ # 拷贝脚本到/tmp目录 RUN cd /tmp && chmod +x setup.sh \ # 添加执行权限 && ./setup.sh && rm setup.sh # 运行脚本然后再删除 -
ADD和COPY目标目录不存在都会自动创建 ,ADD自动去解压缩文件,不推荐使用ADD(过多的操作让它的含义模糊)
dockerfileCOPY ./a.txt /tmp/a.txt # 把构建上下文里的a.txt拷贝到镜像的/tmp目录 COPY /etc/hosts /tmp # 错误!不能使用构建上下文之外的文件 -
ENV设置的变量可以保存在镜像构建中和容器运行时可见,ARG只在镜像中可见
dockerfileARG IMAGE_BASE="node" ARG IMAGE_TAG="alpine" ENV PATH=$PATH:/tmp ENV DEBUG=OFF -
docker build 需要指定"构建上下文",其中的文件会打包上传到 Docker daemon,所以尽量不要在"构建上下文"中存放多余的文件
.dockerignore文件
.dockerignore# docker ignore *.swp *.sh -
可以使用
docker history命令回放完整的镜像的构建过程,有的时候对于镜像排错很有用。 -
尽量使用非root用户
-
建议使用exec的列表格式可以使用env环境变量
-
容器启动命令 CMD,容器启动时默认执行的命令, 启动容器时指定了其它命令,则CMD命令会被忽略
-
构建缓存
-
构建时不使用用缓存 docker build --no-cache -t [镜像名]:[镜像版本]
-
部分使用缓存,dockerfile中指定REFRESH_DATE环境变量
ENV REFRESH_DATE 2018-01-12- 只要构建的缓存时间不变,那么就用缓存,如果时间一旦改变,就不用缓存了
-