Dockerfile使用指南
- 通过RUN执行指令
- Dockerfile
- 改进版Dockerfile
- 文件复制和目录操作(ADD,COPY,WORKDIR)
- 复制普通文件
- 复制压缩文件
- 构建参数和环境变量(ARG vs ENV)
- ENV
- ARG
- 区别
- 容器启动命令CMD
- 容器启动命令ENTRYPOINT
- Shell格式和Exce格式
- Shell格式
- Excel格式
通过RUN执行指令
run 只要勇于在image里执行指令,比如安装软件、下载文件等。
Dockerfile
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
镜像的大小和分层
$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
ipinfo latest 97bb429363fb 4 minutes ago 138MB
ubuntu 21.04 478aa0080b60 4 days ago 74.1MB
$ docker image history 97b
IMAGE CREATED CREATED BY SIZE COMMENT
97bb429363fb 4 minutes ago RUN /bin/sh -c rm -rf ipinfo_2.0.1_linux_amd… 0B buildkit.dockerfile.v0
<missing> 4 minutes ago RUN /bin/sh -c mv ipinfo_2.0.1_linux_amd64 /… 9.36MB buildkit.dockerfile.v0
<missing> 4 minutes ago RUN /bin/sh -c tar zxf ipinfo_2.0.1_linux_am… 9.36MB buildkit.dockerfile.v0
<missing> 4 minutes ago RUN /bin/sh -c wget https://github.com/ipinf… 4.85MB buildkit.dockerfile.v0
<missing> 4 minutes ago RUN /bin/sh -c apt-get install -y wget # bui… 7.58MB buildkit.dockerfile.v0
<missing> 4 minutes ago RUN /bin/sh -c apt-get update # buildkit 33MB buildkit.dockerfile.v0
<missing> 4 days ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B
<missing> 4 days ago /bin/sh -c mkdir -p /run/systemd && echo 'do… 7B
<missing> 4 days ago /bin/sh -c [ -z "$(apt-get indextargets)" ] 0B
<missing> 4 days ago /bin/sh -c set -xe && echo '#!/bin/sh' > /… 811B
<missing> 4 days ago /bin/sh -c #(nop) ADD file:d6b6ba642344138dc… 74.1MB
每一行的RUN命令都会产生一层image layer,导致镜像的臃肿。
改进版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
$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
ipinfo-new latest fe551bc26b92 5 seconds ago 124MB
ipinfo latest 97bb429363fb 16 minutes ago 138MB
ubuntu 21.04 478aa0080b60 4 days ago 74.1MB
$ docker image history fe5
IMAGE CREATED CREATED BY SIZE COMMENT
fe551bc26b92 16 seconds ago RUN /bin/sh -c apt-get update && apt-get… 49.9MB buildkit.dockerfile.v0
<missing> 4 days ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B
<missing> 4 days ago /bin/sh -c mkdir -p /run/systemd && echo 'do… 7B
<missing> 4 days ago /bin/sh -c [ -z "$(apt-get indextargets)" ] 0B
<missing> 4 days ago /bin/sh -c set -xe && echo '#!/bin/sh' > /… 811B
<missing> 4 days ago /bin/sh -c #(nop) ADD file:d6b6ba642344138dc… 74.1MB
$
文件复制和目录操作(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目录如果不存在会自动从创建。
复制压缩文件
ADD比COPY高级一点的地方就是,如果复制的是一个gzip等压缩文件时,ADD会帮我们自动解压。
FROM python:3.9.5-alpine3.13
ADD hello.tar.gz /app/
构建参数和环境变量(ARG vs ENV)
ARG和ENV都可以用来设置一个“变量”。但实际上两者有很多的不同。
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
区别
ARG可以在镜像build的时候动态修改value,通过–build-arg
$ docker image build -f .\Dockerfile-arg -t ipinfo-arg-2.0.0 --build-arg VERSION=2.0.0 .
$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
ipinfo-arg-2.0.0 latest 0d9c964947e2 6 seconds ago 124MB
$ docker container run -it ipinfo-arg-2.0.0
root@b64285579756:/#
root@b64285579756:/# ipinfo version
2.0.0
root@b64285579756:/#
ENV设置的变量可以在Image中保持,并在容器中的环境变量里
容器启动命令CMD
CMD可以用来设置容器启动时默认会执行的命令。
- 容器启动时默认执行的命令
- 如果docker container run启动容器时指定了其它命令,则CMD命令会被忽略
- 如果定义了多个CMD,只有最后一个会被执行
$ docker container run -it alpine:latest
/ #
/ # pwd
/
/ #
默认进入到shell是因为在alpine的镜像里有定义CMD
$ docker image history alpine:latest
IMAGE CREATED CREATED BY SIZE COMMENT
c059bfaa849c 19 months ago /bin/sh -c #(nop) CMD ["/bin/sh"] 0B
<missing> 19 months ago /bin/sh -c #(nop) ADD file:9233f6f2237d79659… 5.59MB
容器启动命令ENTRYPOINT
ENTRYPOINT也可以设置容器启动时要执行的命令,但是和CMD是有区别的。
- CMD设置的命令,可以在docker run时传入其它命令,覆盖掉CMD的命令,但是ENTRYPOINT所设置的命令是一定会被执行的。
- ENTRYPOINT和CMD可以联合使用,ENTRYPOINT设置执行的命令,CMD传递参数。
FROM ubuntu:20.04
CMD ["echo", "hello docker"]
把上面的Dockerfile build成一个叫 demo-cmd的镜像
$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
demo-cmd latest 5bb63bb9b365 8 days ago 74.1MB
FROM ubuntu:20.04
ENTRYPOINT ["echo", "hello docker"]
build成一个叫 demo-entrypoint的镜像
$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
demo-entrypoint latest b1693a62d67a 8 days ago 74.1MB
CMD的镜像,如果执行创建容器,不指定运行时的命令,则会默认执行CMD所定义的命令,打印出hello docker
$ docker container run -it --rm demo-cmd
hello docker
但是如果docker run的时候指定命令,则该命令会覆盖掉CMD的命令,如:
$ docker container run -it --rm demo-cmd echo "hello world"
hello world
但是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
$
Shell格式和Exce格式
CMD和ENTRYPOINT同时支持shell格式和Excel格式。
Shell格式
CMD echo "hello docker"
ENTRYPOINT echo "hello docker"
Excel格式
ENTRYPOINT ["echo", "hello docker"]
CMD ["echo", "hello docker"]
注意shell脚本的问题
FROM ubuntu:20.04
ENV NAME=docker
CMD echo "hello $NAME"
如果将上面的CMD改成Excel格式,是不可行的。
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"]