Dockerfile编写指南

574 阅读3分钟

最近因为项目需要,得学习一下如何编写Dockerfile,以往打docker都是网上copy一段文字,然后改改就直接拿来使用的,但是这次因为项目的特殊性,我们需要从0开始编写一个dockerfile文件来实现打包,所以特地去学习一下,写此文章用以记录。

什么是Dockerfile

dockerfile是一种用来构建镜像的脚本,可以通过dockerfile调用任何系统的命令,比如apt install或者yum install等,当然这些命令都是通过RUN,ADD,COPY,EXPOSE等指令组合而成的,所以学好这些指令,是能否编写一个正确的Dockerfile的关键。

Dockerfile基本结构

下面是一个dockerfile的基本结构

FROM 基础镜像
​
RUN 运行相关依赖,包括安装
​
COPY OR ADD 复制相关文件
​
CMD 执行相关shell命令
​
WORKDIR 类似于Linux中的CD
​
EXPOSE 指定于外界交互的端口
​
ARG 用于指定传递给构建运行时的变量

FROM:

设置基础镜像,一般的话用于指定基础镜像,必须为第一个命令。比如我这是一个Java项目那么我们可以指定为FROM OpenJdk 8这样,然后接下来所有的操作都是基于这个基础镜像在进行构建。

RUN:

构建过程中所执行的命令,假如第一个FROM我们指定的是非系统镜像,那么接下来的环境大概率是Ubuntu,此时我们所运行的命令那么都需要在Ubuntu之上。这一点是需要注意的。

RUN指令创建的中间镜像会被缓存,并会在下次构建中使用。如果不想使用这些缓存镜像,可以在构建时指定--no-cache参数,如:docker build --no-cache。

ADD和COPY:

这两个命令主要是用于复制文件,使用其中一个都可以。不过这里建议使用ADD,ADD支持访问网络,同时可以解压tar文件,功能会比COPY更加强大。

WORKDIR:

类似CD命令,不过强大之处是支持假如文件不存在,会自动创建,并跳转过去。肯定会有精神小伙问,我们不可以用 RUN cd /path 吗?答案是不可,因为docker和Linux还是有区别的。

EXPOSE:

这个就很好理解就是外界暴露的端口,比如mysql的docker一定会暴露3306,redis一定会暴露6375。

ARG:

多用于传参,比如docker run的时候需要传入的参数,都可以在这里定制。

ENTRYPOINT:

和CMD的区别就是entrypoint可以追加参数,CMD只能固定执行。

一个简单Dockerfile例子

接下来,我们通过一个例子更好的说明上述语法的用法,我们这里以python框架OneForAll为例子。

项目地址:github.com/shmilylty/O…

这是一个我们使用到的扫描工具,当然项目不仅是这些,这里我只是简单描述。

FROM centos:8  #(这里以centos为基础镜像的原因和我们项目有关,各位不必参考,建议直接使用所依赖的环境作为基础镜像,比如python,JDK之类的)
​
MAINTAINER huancheng@qq.com # 这里写自己的标识# 配置环境依赖
RUN sudo sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-* \
  && sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-*
​
# 更新系统
RUN sudo yum update -y
​
# 安装python(一定要在环境依赖之后,引擎centos8的源有点问题)
RUN dnf install python36
​
# 跳转到项目目录下
WORKDIR /root/pyproject 
​
RUN dnf install git && git clone https://github.com/shmilylty/OneForAll.git
​
# 安装相关依赖
WORKDIR /root/pyproject/OneForAll
RUN python3 -m venv venv/ && source venv/bin/active && pip3 install -r requirement.txt
​
# 定制执行扫描逻辑
ENTRYPOINT ["python", "oneforall.py"]

完成上述文件,我们docker build一下,然后docker run一下即可。

docker build -t demo:v1 # 构建镜像
docker run imageId # 执行镜像
# 当然oneforall的可选参数很多,我们这里可以进行如下操作
docker run imageId --target qq.com  # 这样也是可以的。全部得益于,我们的ENTRYPOINT逻辑,这就是其和CMD的差距所在

参考

[1] github.com/shmilylty/O… oneforall仓库

[2] yeasy.gitbook.io/docker_prac… Docker 从入门到实践

[3] www.idcbuy.net/it/linux/24… centos 踩坑记录