Appearance
Dockerfile 是一个文本文件,其内包含了一条条的指令(Instruction),用于构建镜像。每一条指令构建一层镜像,因此每一条指令的内容,就是描述该层镜像应当如何构建。
dockerHub官网:Docker Hub 常用命令如下:
- FROM:基于哪个镜像
- MAINTAINER:注明作者
- COPY:复制文件进入镜像(只能用相对路径,不能用绝对路径)
- ADD:复制文件进入镜像(假如文件是.tar.gz文件会解压)
- WORKDIR:指定工作目录,假如路径不存在会创建路径
- ENV:设置环境变量
- EXPOSE:暴露容器端口
- RUN:在构建镜像的时候执行,作用于镜像层面
- ENTRYPOINT:在容器启动的时候执行,作用于容器层,dockerfile里有多条时只允许执行最后一条
- CMD:在容器启动的时候执行,作用于容器层,
- dockerfile里有多条时只允许执行最后一条。
- 容器启动后执行默认的命令或者参数,允许被修改
- 命令格式:
- shell命令格式:RUN yum install -y net-tools
- exec命令格式:RUN [ "yum","install" ,"-y" ,"net-tools"]
1.基础镜像的选择
基本原则如下
- 官方镜像优于非官方的镜像,如果没有官方镜像,则尽量选择Dockerfile开源的
- 固定版本tag而不是每次都使用latest
FROM nginx:1.21.0-alpine - 尽量选择体积小的镜像
- 如何区分官方镜像? —— 搜索后的前几个(verified content下的都是)
实践练习:
假如我们有一个 index.html 文件
html
<h1>Hello Docker</h1>准备一个Dockerfile
dockerfile
FROM nginx:1.21.0-alpine
ADD index.html /usr/share/nginx/html/index.html构建命令
shell
docker image build -t 镜像名称2.通过RUN执行命令
RUN 主要用于在Image里执行指令,比如安装软件,下载文件等。
shell
apt-get update
apt-get install 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.gz2.1 举例说明
说明:下面这种写法是有问题的,虽然可以执行,但是每一行的RUN命令都会产生一层image layer, 导致镜像的臃肿。
dockerfile
FROM ubuntu:21.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.gz2.2 构建命令改进
FROM ubuntu:21.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.gz3.文件复制和目录操作
往镜像里复制文件有两种方式,COPY 和 ADD 都可以把local的一个文件复制到镜像里,如果目标目录不存在,则会自动创建
dockerfile
FROM python:3.9.5-alpine3.13
COPY hello.py /app/hello.py比如把本地的 hello.py 复制到 /app 目录下。 /app这个folder不存在,则会自动创建
3.1 复制压缩文件
ADD 比 COPY高级一点的地方就是,如果复制的是一个gzip等压缩文件时,ADD会帮助我们自动去解压缩文件。
dockerfile
FROM python:3.9.5-alpine3.13
ADD hello.tar.gz /app/因此在 COPY 和 ADD 指令中选择的时候,可以遵循这样的原则,所有的文件复制均使用 COPY 指令,仅在需要自动解压缩的场合使用 ADD。
4. 构建参数和环境变量
ARG 和 ENV 是经常容易被混淆的两个Dockerfile的语法,都可以用来设置一个“变量”。 但实际上两者有很多的不同。
首先看使用前的镜像构建,注意2.0.1
dockerfile
FROM ubuntu:21.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.gz4.1 ENV方式
dockerfile
FROM ubuntu:21.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.gz4.2 ARG方式
dockerfile
FROM ubuntu:21.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.gz4.3 区别
- ARG:构建镜像后,遍历不存在
- ENV:构建镜像后,存在系统变量中,进入镜像容器中,输入env可以看到环境变量

5.容器启动命令 CMD
CMD可以用来设置容器启动时默认会执行的命令。
- 容器启动时默认执行的命令
- 如果docker container run启动容器时指定了其它命令,则CMD命令会被忽略
- 如果定义了多个CMD,只有最后一个会被执行。
- 容器启动后执行默认的命令或者参数,允许被修改
dockerfile
FROM ubuntu:21.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
CMD ["echo","containe1r","starting..."]6.容器启动命令 ENTRYPOINT
ENTRYPOINT 也可以设置容器启动时要执行的命令,但是和CMD是有区别的。
CMD设置的命令,可以在docker container run 时传入其它命令,覆盖掉CMD的命令,但是ENTRYPOINT所设置的命令是一定会被执行的。ENTRYPOINT和CMD可以联合使用,ENTRYPOINT设置执行的命令,CMD传递参数
dockerfile
FROM centos:7
RUN echo "images building!"
CMD ["echo","container","starting..."]
ENTRYPOINT ["echo","container","starting !!!"]运行举例:同样的命令,如果使用RUN, echo "hello world" 会将其覆盖,但是使用ENTRYPOINT则不会受到影响
shell
docker container run -it --rm demo-cmd echo "hello world"7.Shell 格式和 Exec 格式
7.1 Shell格式
CMD echo "hello docker"
ENTRYPOINT echo "hello docker"7.2 Exec格式
以可执行命令的方式
dockerfile
ENTRYPOINT ["echo", "hello docker"]
CMD ["echo", "hello docker"]注意shell脚本的问题
shell
FROM ubuntu:21.04
ENV NAME=docker
CMD echo "hello $NAME"假如我们要把上面的CMD改成Exec格式,下面这样改是不行的, 大家可以试试。
dockerfile
FROM ubuntu:21.04
ENV NAME=docker
CMD ["echo", "hello $NAME"]它会打印出 hello $NAME , 而不是 hello docker ,那么需要怎么写呢? 我们需要以shell脚本的方式去执行
dockerfile
FROM ubuntu:21.04
ENV NAME=docker
CMD ["sh", "-c", "echo hello $NAME"]