Choosing Base Docker Images
基础镜像的选择 (FROM)
- 官方Image优于非官方的Image,如果没有官方Image,则尽量ChooseDockerfile开源的
- 固定Versiontag而不是每次都Usagelatest
- 尽量Choose体积小的Image
空Image:scratch
最小Image:alpine
通过 RUN 执行指令
RUN 主要用于在Image里Execute指令,比如Installation软件,DownloadFile等。
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
每Execute一次RUNExecute,就会新产生一个分层。
一般Usage,Optimization后的ExecuteCommand:
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
&&:指令拼接
\:Command换行。
只Execute了一次RUN,则只会产生一个分层。
文件复制和目录操作
(ADD,COPY,WORKDIR)
往Image里复制File有两种方式,COPY 和 ADD , 我们来看一下两者的不同。
复制普通文件
COPY 和 ADD 都可以把local的一个File复制到Image里,如果目标Directory不存在,则会自动Create。
FROM python:3.9.5-alpine3.13
COPY hello.py /app/hello.py
比如把本地的 hello.py 复制到 /app Directory下。 /app这个folder不存在,则会自动Create。
复制压缩文件
ADD 比 COPY高级一点的地方就是,如果复制的是一个gzip等压缩File时,ADD会帮助我们自动去解压缩File。
FROM python:3.9.5-alpine3.13
ADD hello.tar.gz /app/
所有的File复制均Usage COPY 指令,仅在需要自动解压缩的场合Usage ADD。
注意:对应File的Permissions复制到BasicImage里面后Permissions一样。
目录切换
WORKDIR:Directory切换,类似cd的操作。比cd好的是,没有Directory时,会帮自动Create。
FROM python:3.9.5-alpine3.13
WORKDIR /app
COPY hello.py hello.py
WORKDIR切换Directory后,copy默认copy到切换后的appDirectory下。
构建参数和环境变量 (ARG vs ENV)
ARG 和 ENV 是经常容易被混淆的两个Dockerfile的Syntax,都可以用来Settings一个“变量”。 但实际上两者有很多的不同。
例子:Installation某个特定Version软件时,需要对Version进行升级,就可以定义Parameter变量,方便后续升级,直接改Version号即可。
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
上面是没有Usage变量时,每次升级就需要改Version号2.0.1,这样会修改很多地方,这时就可以定义Parameter变量,之后升级改一个地方就可以了。
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
Usage时,都是${变量名}这样Usage。如果要改Version,这样直接改VERSION=新Version号就可以了。
ENV与ARG区别
ARG:只作用域ImageBuild过程中,Image环境中是没有该Parameter的,后续Container中不能Usage改Parameter变量。buildImage时可以UsageParameter—build-arg动态改变Parameter值。
例如:
docker image build -f .\Dockerfile-arg -t ipinfo-arg-2.0.0 --build-arg VERSION=2.0.0 .
ENV:会将ParameterSettings到Image中,通过env可以看到环境变量中有对应的Parameter,后续Container中也可以Usage这些Parameter变量。不能动态改值。
使用场景
ARG主要用于关注buildImage的过程。
ENV主要用于后续Container中Usage。
容器启动时默认执行的命令 CMD
CMD可以用来SettingsContainerStart时默认会Execute的Command。
- ContainerStart时默认Execute的Command
- 如果docker container runStartContainer时指定了其它Command,则CMDCommand会被忽略
- 如果定义了多个CMD,只有最后一个会被Execute。
1、清理后台已经停止的全部Container:
docker system prune -f
也可以一个一个清理
docekr container rm 容器名称
2、删除没有用到的全部Image
docker image prune -a
当没有定义CMDCommand时,会默认进入到shell是因为在ubuntu的BasicImage里有定义CMD。
如果想一次行RunContainer,Run完后自动删除Container:只需要在RunContainer时加Parameter—rm即可。
容器启动命令 ENTRYPOINT
ENTRYPOINT 也可以SettingsContainerStart时要Execute的Command,但是和CMD是有区别的。
CMDSettings的Command,可以在docker container run 时传入其它Command,覆盖掉CMD的Command,但是ENTRYPOINT所Settings的Command是一定会被Execute的。ENTRYPOINT和CMD可以联合Usage,ENTRYPOINTSettingsExecute的Command,CMD传递Parameter。
1、CMDCommand的Dockerfile,build成一个叫 demo-cmd 的镜象。
FROM ubuntu:20.04
CMD ["echo", "hello docker"]
2、ENTRYPOINTCommand的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的时候指定Command,则该Command会覆盖掉CMD的Command:
$ 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”当作Parameter传入。
3、CMD作为ParameterParameter传入ENTRYPOINT,Dockerfile如下:
FROM ubuntu:21.04
ENTRYPOINT ["echo"]
CMD []
将3Compile成叫demoboth的Image。
docker run --rm -it demoboth
不加cmdExecute:Executeecho打印了空行
[root@10 ~]# docker run --rm -it demoboth:1.0
加cmd传入作为echo的Parameter打出:
[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格式
以可ExecuteCommand的方式
ENTRYPOINT ["echo", "hello docker"]
CMD ["echo", "hello docker"]
注意shellScript的Problem
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 ,那么需要怎么写呢? 我们需要以shellScript的方式去Execute:
FROM ubuntu:20.04
ENV NAME=docker
CMD ["sh", "-c", "echo hello $NAME"]
“sh”:ExecuteshCommand
“-c”: Execute的Command