基础镜像的选择 (FROM)
- 官方镜像优于非官方的镜像,如果没有官方镜像,则尽量选择Dockerfile开源的
- 固定版本tag而不是每次都使用latest
- 尽量选择体积小的镜像
空镜像:scratch
最小镜像:alpine
通过 RUN 执行指令
RUN
主要用于在Image里执行指令,比如安装软件,下载文件等。
FROM ubuntu:20.04
RUN apt-get update
RUN apt-get install -y wget
RUN wget https://github.com/ipinfo/cli/releases/download/ipinfo-2.0.1/ipinfo_2.0.1_linux_amd64.tar.gz
RUN tar zxf ipinfo_2.0.1_linux_amd64.tar.gz
RUN mv ipinfo_2.0.1_linux_amd64 /usr/bin/ipinfo
RUN rm -rf ipinfo_2.0.1_linux_amd64.tar.gz
每执行一次RUN执行,就会新产生一个分层。
一般使用,优化后的执行命令:
FROM ubuntu:20.04
RUN apt-get update && \
apt-get install -y wget && \
wget https://github.com/ipinfo/cli/releases/download/ipinfo-2.0.1/ipinfo_2.0.1_linux_amd64.tar.gz && \
tar zxf ipinfo_2.0.1_linux_amd64.tar.gz && \
mv ipinfo_2.0.1_linux_amd64 /usr/bin/ipinfo && \
rm -rf ipinfo_2.0.1_linux_amd64.tar.gz
&&:指令拼接
\:命令换行。
只执行了一次RUN,则只会产生一个分层。
文件复制和目录操作
(ADD,COPY,WORKDIR)
往镜像里复制文件有两种方式,COPY
和 ADD
, 我们来看一下两者的不同。
复制普通文件
COPY
和 ADD
都可以把local的一个文件复制到镜像里,如果目标目录不存在,则会自动创建。
FROM python:3.9.5-alpine3.13
COPY hello.py /app/hello.py
比如把本地的 hello.py 复制到 /app 目录下。 /app这个folder不存在,则会自动创建。
复制压缩文件
ADD
比 COPY高级一点的地方就是,如果复制的是一个gzip等压缩文件时,ADD会帮助我们自动去解压缩文件。
FROM python:3.9.5-alpine3.13
ADD hello.tar.gz /app/
所有的文件复制均使用 COPY 指令,仅在需要自动解压缩的场合使用 ADD。
注意:对应文件的权限复制到基础镜像里面后权限一样。
目录切换
WORKDIR:目录切换,类似cd的操作。比cd好的是,没有目录时,会帮自动创建。
FROM python:3.9.5-alpine3.13
WORKDIR /app
COPY hello.py hello.py
WORKDIR切换目录后,copy默认copy到切换后的app目录下。
构建参数和环境变量 (ARG vs ENV)
ARG
和 ENV
是经常容易被混淆的两个Dockerfile的语法,都可以用来设置一个“变量”。 但实际上两者有很多的不同。
例子:安装某个特定版本软件时,需要对版本进行升级,就可以定义参数变量,方便后续升级,直接改版本号即可。
FROM ubuntu:20.04
RUN apt-get update && \
apt-get install -y wget && \
wget https://github.com/ipinfo/cli/releases/download/ipinfo-2.0.1/ipinfo_2.0.1_linux_amd64.tar.gz && \
tar zxf ipinfo_2.0.1_linux_amd64.tar.gz && \
mv ipinfo_2.0.1_linux_amd64 /usr/bin/ipinfo && \
rm -rf ipinfo_2.0.1_linux_amd64.tar.gz
上面是没有使用变量时,每次升级就需要改版本号2.0.1,这样会修改很多地方,这时就可以定义参数变量,之后升级改一个地方就可以了。
ENV变量
FROM ubuntu:20.04
ENV VERSION=2.0.1
RUN apt-get update && \
apt-get install -y wget && \
wget https://github.com/ipinfo/cli/releases/download/ipinfo-${VERSION}/ipinfo_${VERSION}_linux_amd64.tar.gz && \
tar zxf ipinfo_${VERSION}_linux_amd64.tar.gz && \
mv ipinfo_${VERSION}_linux_amd64 /usr/bin/ipinfo && \
rm -rf ipinfo_${VERSION}_linux_amd64.tar.gz
ARG变量
FROM ubuntu:20.04
ARG VERSION=2.0.1
RUN apt-get update && \
apt-get install -y wget && \
wget https://github.com/ipinfo/cli/releases/download/ipinfo-${VERSION}/ipinfo_${VERSION}_linux_amd64.tar.gz && \
tar zxf ipinfo_${VERSION}_linux_amd64.tar.gz && \
mv ipinfo_${VERSION}_linux_amd64 /usr/bin/ipinfo && \
rm -rf ipinfo_${VERSION}_linux_amd64.tar.gz
使用时,都是${变量名}这样使用。如果要改版本,这样直接改VERSION=新版本号就可以了。
ENV与ARG区别
ARG:只作用域镜像构建过程中,镜像环境中是没有该参数的,后续容器中不能使用改参数变量。build镜像时可以使用参数--build-arg动态改变参数值。
例如:
docker image build -f .\Dockerfile-arg -t ipinfo-arg-2.0.0 --build-arg VERSION=2.0.0 .
ENV:会将参数设置到镜像中,通过env可以看到环境变量中有对应的参数,后续容器中也可以使用这些参数变量。不能动态改值。
使用场景
ARG主要用于关注build镜像的过程。
ENV主要用于后续容器中使用。
容器启动时默认执行的命令 CMD
CMD可以用来设置容器启动时默认会执行的命令。
- 容器启动时默认执行的命令
- 如果docker container run启动容器时指定了其它命令,则CMD命令会被忽略
- 如果定义了多个CMD,只有最后一个会被执行。
1、清理后台已经停止的全部容器:
docker system prune -f
也可以一个一个清理
docekr container rm 容器名称
2、删除没有用到的全部镜像
docker image prune -a
当没有定义CMD命令时,会默认进入到shell是因为在ubuntu的基础镜像里有定义CMD。
如果想一次行运行容器,运行完后自动删除容器:只需要在运行容器时加参数--rm即可。
容器启动命令 ENTRYPOINT
ENTRYPOINT 也可以设置容器启动时要执行的命令,但是和CMD是有区别的。
CMD
设置的命令,可以在docker container run 时传入其它命令,覆盖掉CMD
的命令,但是ENTRYPOINT
所设置的命令是一定会被执行的。ENTRYPOINT
和CMD
可以联合使用,ENTRYPOINT
设置执行的命令,CMD传递参数。
1、CMD命令的Dockerfile,build成一个叫 demo-cmd
的镜象。
FROM ubuntu:20.04
CMD ["echo", "hello docker"]
2、ENTRYPOINT命令的Dockerfile,build成一个叫 demo-entrypoint
的镜象。
FROM ubuntu:20.04
ENTRYPOINT ["echo", "hello docker"]
比较:
CMD的镜像,如果执行创建容器,不指定运行时的命令,则会默认执行CMD所定义的命令,打印出hello docker
$ docker container run -it --rm demo-cmd
hello docker
如果我们docker container run的时候指定命令,则该命令会覆盖掉CMD的命令:
$ docker container run -it --rm demo-cmd echo "hello world"
hello world
ENTRYPOINT的容器里ENTRYPOINT所定义的命令则无法覆盖,一定会执行:
$ docker container run -it --rm demo-entrypoint
hello docker
$ docker container run -it --rm demo-entrypoint echo "hello world"
hello docker echo hello world
会将echo "hello world"当作参数传入。
3、CMD作为参数参数传入ENTRYPOINT,Dockerfile如下:
FROM ubuntu:21.04
ENTRYPOINT ["echo"]
CMD []
将3编译成叫demoboth的镜像。
docker run --rm -it demoboth
不加cmd执行:执行echo打印了空行
[root@10 ~]# docker run --rm -it demoboth:1.0
加cmd传入作为echo的参数打出:
[root@10 ~]# docker run --rm -it demoboth:1.0 echo "hi docker"
echo hi docker
Shell 格式和 Exec 格式
Shell格式
CMD echo "hello docker"
ENTRYPOINT echo "hello docker"
Exec格式
以可执行命令的方式
ENTRYPOINT ["echo", "hello docker"]
CMD ["echo", "hello docker"]
注意shell脚本的问题
FROM ubuntu:20.04
ENV NAME=docker
CMD echo "hello $NAME"
假如我们要把上面的CMD改成Exec格式,下面这样改是不行的。
FROM ubuntu:20.04
ENV NAME=docker
CMD ["echo", "hello $NAME"]
它会打印出 hello $NAME
, 而不是 hello docker
,那么需要怎么写呢? 我们需要以shell脚本的方式去执行:
FROM ubuntu:20.04
ENV NAME=docker
CMD ["sh", "-c", "echo hello $NAME"]
"sh":执行sh命令
“-c”: 执行的命令
评论 (0)