一. Dockerfile
Dockerfile可以理解为是 “专门用于构建镜像的shell脚本”,用户可以通过自定义 Dockerfile 内容来快速构建镜像。
二. Dockerfile指令说明
指令 | 说明 | 使用 |
---|---|---|
FROM | 指定基础镜像 | FROM centos |
MAINTAINER | 作者及邮箱 | author、email |
RUN | 镜像构建中需要运行的命令 | RUN yum -y install vim |
ADD | 将本地文件拷贝到镜像中,可以访问网络资源。如果跟的是一个远程文件url的话就会自动下载该文件并将其添加进目标路径下;如果是tar类型文件就会自动解压(网络压缩资源比如远程的tar文件,就不会被解压) | ADD apache-tomcat-9.0.22.tar.gz /usr/local/ # 将tomcat解压到/usr/local/目录下 |
COPY | 功能类似ADD,但是不会自动解压文件,也不能访问网络资源 | COPY . /webapp # 把当前本地目录下的文件复制到镜像中的webapp目录下 |
ENV | 设置环境变量,这个值将出现在构建阶段中所有后续指令的环境中 | ENV MYPATH /usr/local |
WORKDIR | 镜像的工作目录(如果没有这个目录会自动创建),可以有多个WORKDIR | WORKDIR $MYPATH |
VOLUME | 挂载的目录 | VOLUME [“volume01”, “volume02”] # 将容器内的两个目录挂在到宿主机 |
EXPOSE | 暴露容器的端口配置 | EXPOSE 9090 |
CMD | 指定这个容器启动的时候要运行的命令(只有最后一个会生效) | 见下文 |
EMTRYPOINT | 指定这个容器启动的时候要运行的命令,可以追加命令 | 见下文 |
三. Dockerfile之CMD、ENTRYPOINT
3.1 CMD
CMD:指定该容器启动时要运行的命令,如果在Dockerfile中有多条CMD指令,那么最后一条CMD指令会将之前的所有CMD指令覆盖掉;如果在命令行追加新命令时,新命令会把旧命令覆盖掉,也只有最后一个会生效。
我们来测试下CMD指令。
# 构建dockerfile文件
cat dockerfile_cmd
FROM centos
CMD echo "dockerfile_cmd test"
CMD ["ls", "-a"]
# 构建镜像
# 如果dockerfile文件名就叫"dockerfile",那么构建镜像的命令就不用加 -f 指定文件名 参数了,直接docker build -t ...
docker build -f dockerfile_cmd -t dockerfile_cmd:1.0 .
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
dockerfile_cmd 1.0 054062dfdeea 22 minutes ago 231MB
centos latest 5d0da3dc9764 5 months ago 231MB
运行该镜像后,只打印出CMD的【“ls”, “-a”】命令。
docker run dockerfile_cmd:1.0
.
..
.dockerenv
bin
dev
etc
home
lib
lib64
lost+found
media
mnt
opt
proc
root
run
sbin
srv
sys
tmp
usr
var
我们尝试着启动时再加一些命令及参数,结果我们只看到了第二次新添加的指令生效了,Dockerfile中的 ls -a 并没有生效,说明了CMD指令是以最后一次为准。
docker run dockerfile_cmd:1.0 ls -l
total 0
lrwxrwxrwx 1 root root 7 Nov 3 2020 bin -> usr/bin
drwxr-xr-x 5 root root 340 Feb 28 13:05 dev
drwxr-xr-x 1 root root 66 Feb 28 13:05 etc
drwxr-xr-x 2 root root 6 Nov 3 2020 home
lrwxrwxrwx 1 root root 7 Nov 3 2020 lib -> usr/lib
lrwxrwxrwx 1 root root 9 Nov 3 2020 lib64 -> usr/lib64
drwx------ 2 root root 6 Sep 15 14:17 lost+found
drwxr-xr-x 2 root root 6 Nov 3 2020 media
drwxr-xr-x 2 root root 6 Nov 3 2020 mnt
drwxr-xr-x 2 root root 6 Nov 3 2020 opt
dr-xr-xr-x 151 root root 0 Feb 28 13:05 proc
dr-xr-x--- 2 root root 162 Sep 15 14:17 root
drwxr-xr-x 11 root root 163 Sep 15 14:17 run
lrwxrwxrwx 1 root root 8 Nov 3 2020 sbin -> usr/sbin
drwxr-xr-x 2 root root 6 Nov 3 2020 srv
dr-xr-xr-x 13 root root 0 Feb 28 13:05 sys
drwxrwxrwt 7 root root 171 Sep 15 14:17 tmp
drwxr-xr-x 12 root root 144 Sep 15 14:17 usr
drwxr-xr-x 20 root root 262 Sep 15 14:17 var
可以理解为run命令行添加的指令替换了原Dockerfile中的CMD,所以run命令行的指令必须得是指令+参数的形式(ls -l,不能单单加个参数 -l),否则报错。
docker run 054062dfdeea -l
docker: Error response from daemon: OCI runtime create failed: container_linux.go:380: starting container process caused: exec: "-l": executable file not found in $PATH: unknown.
3.2 ENTRYPOINT
ENTRYPOINT:指定该容器启动时要运行的命令,新的 ENTRYPOINT 指令也会将旧的覆盖掉。可以在docker run命令行追加命令参数,新添加的参数会追加到原dockerfile的ENTRYPOINT命令里。
接着测一下ENTRYPOINT指令。
# 构建dockerfile文件
cat dockerfile_entrypoint
FROM centos
ENTRYPOINT ["echo", "dockerfile-entrypoint test"]
ENTRYPOINT ["ls", "-a"]
# 构建镜像
docker build -f dockerfile_entrypoint -t dockerfile_entrypoint:1.0 .
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
dockerfile_entrypoint 1.0 1ce43408e0d2 42 minutes ago 231MB
dockerfile_cmd 1.0 054062dfdeea 4 hours ago 231MB
centos latest 5d0da3dc9764 5 months ago 231MB
运行该镜像后,同样也是输出【“ls”, “-a”】命令。
docker run dockerfile_entrypoint:1.0
.
..
.dockerenv
bin
dev
etc
home
lib
lib64
lost+found
media
mnt
opt
proc
root
run
sbin
srv
sys
tmp
usr
var
我们尝试着再加一些参数,比如 -l,相当于在Dockerfile的ENTRYPOINT里追加了 -l 的参数,即【ls -a -l】。
docker run 1ce43408e0d2 -l
total 0
drwxr-xr-x 1 root root 6 Feb 28 15:51 .
drwxr-xr-x 1 root root 6 Feb 28 15:51 ..
-rwxr-xr-x 1 root root 0 Feb 28 15:51 .dockerenv
lrwxrwxrwx 1 root root 7 Nov 3 2020 bin -> usr/bin
drwxr-xr-x 5 root root 340 Feb 28 15:51 dev
drwxr-xr-x 1 root root 66 Feb 28 15:51 etc
drwxr-xr-x 2 root root 6 Nov 3 2020 home
lrwxrwxrwx 1 root root 7 Nov 3 2020 lib -> usr/lib
lrwxrwxrwx 1 root root 9 Nov 3 2020 lib64 -> usr/lib64
drwx------ 2 root root 6 Sep 15 14:17 lost+found
drwxr-xr-x 2 root root 6 Nov 3 2020 media
drwxr-xr-x 2 root root 6 Nov 3 2020 mnt
drwxr-xr-x 2 root root 6 Nov 3 2020 opt
dr-xr-xr-x 152 root root 0 Feb 28 15:51 proc
dr-xr-x--- 2 root root 162 Sep 15 14:17 root
drwxr-xr-x 11 root root 163 Sep 15 14:17 run
lrwxrwxrwx 1 root root 8 Nov 3 2020 sbin -> usr/sbin
drwxr-xr-x 2 root root 6 Nov 3 2020 srv
dr-xr-xr-x 13 root root 0 Feb 28 13:05 sys
drwxrwxrwt 7 root root 171 Sep 15 14:17 tmp
drwxr-xr-x 12 root root 144 Sep 15 14:17 usr
drwxr-xr-x 20 root root 262 Sep 15 14:17 var
# 这样追加是错误的
docker run 1ce43408e0d2 ls -l
ls: cannot access 'ls': No such file or directory
3.3 如何使用
一般情况下,ENTRYPOINT和CMD都是互相配合使用的,即:ENTRYPOINT填写固定的命令,CMD填写该固定命令对应的参数,CMD将这个参数传递给ENTRYPOINT命令。可以理解为CMD参数为默认值,如果项目中使用的不是CMD的默认值,就可以在启动docker容器时添加上真实的参数值,用来覆盖CMD的默认值。
python-flask项目:
cat Dockerfile
FROM python:3.7-alpine
WORKDIR /code
RUN apk add --no-cache gcc musl-dev linux-headers
COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt
EXPOSE 5000
COPY . .
ENTRYPOINT ["python"]
CMD ["app.py"]
可能项目中的启动文件不叫app.py,叫start.py,那么启动容器时就可以更新该参数:
docker run flask_app:1.0 start.py
java项目:
...其他指令
ENTRYPOINT ["java", "-jar"]
CMD ["cms.jar"]
启动容器时更换成项目中的jar包:
docker run java_app:1.0 startcms.jar
四. 查看镜像的变更历史
docker history 镜像id