基本原则
- 官方镜像优于非官方的镜像,如果没有官方镜像,则尽量选择Dockerfile开源的
- 固定版本tag而不是每次都使用latest
- 尽量选择体积小的镜像
编写第一个Dockerfile文件
# 新建文件夹并进入
mkdir docker-demo && cd docker-demo
# 新增index.html文件
vim index.html
# index.html文件写入内容
echo "<h1>hello docker</h1>" > index.html
# 新增Dockerfile文件
vim Dockerfile
# Dockerfile文件写入内容
echo "FROM nginx:1.21.0-alpine" >> Dockerfile
echo "ADD index.html /usr/share/nginx/html/index.html" >> Dockerfile
# docker镜像build
sudo docker image build -t demonginx .
RUN命令
RUN
主要用于在Image里执行指令,比如安装软件,下载文件等。但是如果有多条RUN
命令,建议多条RUN
命令合并同一 命令。
# 不建议
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
# 建议
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
ADD和COPY命令
COPY
和 ADD
都可以把local的一个文件复制到镜像里,如果目标目录不存在,则会自动创建。比如把本地的 hello.py 复制到 /app 目录下。 /app这个folder不存在,则会自动创建
FROM python:3.9.5-alpine3.13
COPY hello.py /app/hello.py
ADD
比 COPY高级一点的地方就是,如果复制的是一个gzip等压缩文件时,ADD会帮助我们自动去解压缩文件。
FROM python:3.9.5-alpine3.13
ADD hello.tar.gz /app/
因此在 COPY 和 ADD 指令中选择的时候,可以遵循这样的原则,所有的文件复制均使用 COPY 指令,仅在需要自动解压缩的场合使用 ADD。
ARG和ENV命令
ARG
和 ENV
是经常容易被混淆的两个Dockerfile的语法,都可以用来设置一个“变量”。 但实际上两者有很多的不同。
# Dockerfile.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
# Dockerfile.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和ENTRYPOINT命令
CMD可以用来设置容器启动时默认会执行的命令。
- 容器启动时默认执行的命令
- 如果docker container run启动容器时指定了其它命令,则CMD命令会被忽略
- 如果定义了多个CMD,只有最后一个会被执行。
默认进入到shell是因为在ubuntu的基础镜像里有定义CMD
sudo docker image history ipinfo
IMAGE CREATED CREATED BY SIZE COMMENT
cf84840e9eb6 About an hour ago /bin/sh -c #(nop) COPY file:419e7704ddc1c481… 26B
6a94addb9f64 About an hour ago /bin/sh -c #(nop) ENV VERSION=2.0.0 0B
a6eb2a334a9f 16 months ago /bin/sh -c #(nop) CMD ["nginx" "-g" "daemon… 0B
<missing> 16 months ago /bin/sh -c #(nop) STOPSIGNAL SIGQUIT 0B
<missing> 16 months ago /bin/sh -c #(nop) EXPOSE 80 0B
<missing> 16 months ago /bin/sh -c #(nop) ENTRYPOINT ["/docker-entr… 0B
<missing> 16 months ago /bin/sh -c #(nop) COPY file:09a214a3e07c919a… 4.61kB
<missing> 16 months ago /bin/sh -c #(nop) COPY file:0fd5fca330dcd6a7… 1.04kB
<missing> 16 months ago /bin/sh -c #(nop) COPY file:0b866ff3fc1ef5b0… 1.96kB
<missing> 16 months ago /bin/sh -c #(nop) COPY file:65504f71f5855ca0… 1.2kB
<missing> 16 months ago /bin/sh -c set -x && addgroup -g 101 -S … 17MB
<missing> 16 months ago /bin/sh -c #(nop) ENV PKG_RELEASE=1 0B
<missing> 16 months ago /bin/sh -c #(nop) ENV NJS_VERSION=0.5.3 0B
<missing> 16 months ago /bin/sh -c #(nop) ENV NGINX_VERSION=1.21.0 0B
<missing> 17 months ago /bin/sh -c #(nop) LABEL maintainer=NGINX Do… 0B
<missing> 17 months ago /bin/sh -c #(nop) CMD ["/bin/sh"] 0B
<missing> 17 months ago /bin/sh -c #(nop) ADD file:8ec69d882e7f29f06… 5.61MB
CMD的镜像,如果执行创建容器,不指定运行时的命令,则会默认执行CMD所定义的命令。
docker container run -it --rm demo-cmd
但是如果我们docker container run的时候指定命令,则该命令会覆盖掉CMD的命令。
docker container run -it --rm demo-cmd echo "hello world"
ENTRYPOINT 也可以设置容器启动时要执行的命令,但是和CMD是有区别的。
CMD
设置的命令,可以在docker container run 时传入其它命令,覆盖掉CMD
的命令,但是ENTRYPOINT
所设置的命令是一定会被执行的。ENTRYPOINT
和CMD
可以联合使用,ENTRYPOINT
设置执行的命令,CMD传递参数
FROM ubuntu:20.04
ENTRYPOINT ["echo", "hello docker"]
CMD ["echo","hello cmd"]
输出的结果是:
# 这是因为ENTRYPOINT将CMD命令当成参数执行在echo后面了
hello docker echo hello cmd