Fork me on Gitee

Dockerfile完全指南

Dockerfile完全指南

基础镜像的选择

基础原则

  • 官方镜像优于非官方的镜像,如果没有官方镜像,则尽量选择Dockerfile开源的。
  • 固定版本Tag而不是每次都使用lastest
  • 尽力选择体积小的镜像<-alpine 精简版>
[root@node01 ~]# docker images

REPOSITORY           TAG             IMAGE ID       CREATED         SIZE
nginx                latest          f876bfc1cc63   5 weeks ago     192MB
mysql                5.7             5107333e08a8   12 months ago   501MB
nginx                1.21.0          4f380adfc10f   3 years ago     133MB
nginx                1.21.0-alpine   a6eb2a334a9f   3 years ago     22.6MB

可以看到,nginx:1.21.0大小为133MB,而nginx:1.21.0-alpine大小仅22.6MB

通过RUN执行命令

RUN主要用于在Image里执行命令,比如安装软件、下载等。

$ 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.gz

Dockerfile

  • Dockerfile-bad
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

image-20250104120324098

docker image build -f dockerfile.bad -t ipinfo-bad .

镜像的大小和分层

[root@node01 dockerfile]# docker image ls
REPOSITORY           TAG             IMAGE ID       CREATED          SIZE
ipinfo-bad           latest          e5260983907f   15 minutes ago   159MB
zhangshao3/mynginx   1.0             4c17ff0fc31c   5 days ago       192MB
tomcat               latest          f62f518e5c5c   3 weeks ago      467MB
nginx                latest          f876bfc1cc63   5 weeks ago      192MB
mysql                5.7             5107333e08a8   12 months ago    501MB
nginx                1.21.0          4f380adfc10f   3 years ago      133MB
nginx                1.21.0-alpine   a6eb2a334a9f   3 years ago      22.6MB
[root@node01 dockerfile]# docker image history  e526
IMAGE          CREATED          CREATED BY                                      SIZE      COMMENT
e5260983907f   15 minutes ago   RUN /bin/sh -c rm -rf ipinfo_2.0.1_linux_amd…   0B        buildkit.dockerfile.v0
<missing>      15 minutes ago   RUN /bin/sh -c mv ipinfo_2.0.1_linux_amd64 /…   9.36MB    buildkit.dockerfile.v0
<missing>      15 minutes ago   RUN /bin/sh -c tar zxf ipinfo_2.0.1_linux_am…   9.36MB    buildkit.dockerfile.v0
<missing>      15 minutes ago   RUN /bin/sh -c wget https://github.com/ipinf…   4.85MB    buildkit.dockerfile.v0
<missing>      16 minutes ago   RUN /bin/sh -c apt-get install -y wget # bui…   7.65MB    buildkit.dockerfile.v0
<missing>      16 minutes ago   RUN /bin/sh -c apt-get update # buildkit        55.4MB    buildkit.dockerfile.v0
<missing>      2 months ago     /bin/sh -c #(nop)  CMD ["/bin/bash"]            0B
<missing>      2 months ago     /bin/sh -c #(nop) ADD file:7486147a645d8835a…   72.8MB
<missing>      2 months ago     /bin/sh -c #(nop)  LABEL org.opencontainers.…   0B
<missing>      2 months ago     /bin/sh -c #(nop)  LABEL org.opencontainers.…   0B
<missing>      2 months ago     /bin/sh -c #(nop)  ARG LAUNCHPAD_BUILD_ARCH     0B
<missing>      2 months ago     /bin/sh -c #(nop)  ARG RELEASE                  0B

每一行的RUN命令都会产生一层image layer,导致镜像的臃肿

image-20250104122327384

改进后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 build -f dockerfile.good -t ipinfo-good .
[root@node01 dockerfile]# docker images
REPOSITORY           TAG             IMAGE ID       CREATED          SIZE
ipinfo-good          latest          3ec094c48160   30 seconds ago   145MB
ipinfo-bad           latest          e5260983907f   33 minutes ago   159MB
zhangshao3/mynginx   1.0             4c17ff0fc31c   5 days ago       192MB
tomcat               latest          f62f518e5c5c   3 weeks ago      467MB
nginx                latest          f876bfc1cc63   5 weeks ago      192MB
mysql                5.7             5107333e08a8   12 months ago    501MB
nginx                1.21.0          4f380adfc10f   3 years ago      133MB
nginx                1.21.0-alpine   a6eb2a334a9f   3 years ago      22.6MB
[root@node01 dockerfile]# docker image history 3ec094c48160
IMAGE          CREATED          CREATED BY                                      SIZE      COMMENT
3ec094c48160   48 seconds ago   RUN /bin/sh -c apt-get update &&     apt-get…   72.5MB    buildkit.dockerfile.v0
<missing>      2 months ago     /bin/sh -c #(nop)  CMD ["/bin/bash"]            0B
<missing>      2 months ago     /bin/sh -c #(nop) ADD file:7486147a645d8835a…   72.8MB
<missing>      2 months ago     /bin/sh -c #(nop)  LABEL org.opencontainers.…   0B
<missing>      2 months ago     /bin/sh -c #(nop)  LABEL org.opencontainers.…   0B
<missing>      2 months ago     /bin/sh -c #(nop)  ARG LAUNCHPAD_BUILD_ARCH     0B
<missing>      2 months ago     /bin/sh -c #(nop)  ARG RELEASE                  0B

可以观察到,一条命令,只占用72.8MB

image-20250104122353503

文件复制和目录操作

往镜像里复制文件有两种方式,COPYADD

复制普通文件

COPYADD都可以把local的一个文件复制到镜像里,如果目标目录不存在,则会自动创建。

FROM python:3.9.5-alpine3.13
COPY hello.py /app/hello.py

复制压缩文件

ADDCOPY高级一点的地方就是,如果复制的是一个gzip等压缩文件时,ADD会帮助我们自动去解压缩文件。

FROM python:3.9.5-alpine3.13
ADD hello.tar.gz /app/

如何选择

因此在 COPY 和 ADD 指令中选择的时候,可以遵循这样的原则,所有的文件复制均使用 COPY 指令,仅在需要自动解压缩的场合使用 ADD。

# 切换目录,类似于cd, 如果目录不存在,自动创建
WORKDIR /app

构建参数和环境变量

ARGENV是经常易被混淆的两个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

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,只有最后一个会被执行

快速删除已退出的镜像

[root@node01 dockerfile]# docker system prune -f
Deleted Containers:
19775fd1fe8c40d07394eebee075f586a485a3192c03492d72b510ba2515e763
519f513648cdc281a995c69e1f2ecb4f2cc033240ff3dbfba0c3caf078eadc9b
e07a6f8a70f7266a5502bc0c477f831a274f81397ac6e432579a10b433588dd3

Deleted build cache objects:
hez2u8fzodf8afths4nwvtve8
wf9env47fjy7l1h48j6kxhvgz
xh4h2kju1k40362q46k54c1ud

Total reclaimed space: 167.2kB

快速删除所有的镜像

docker image prune -a

创建一个带cmd的dockerfile

FROM ubuntu:20.04
ENV VERSION=2.0.1
# 如果网络情况不佳,可制定阿里源
RUN sed -i 's/archive.ubuntu.com/mirrors.aliyun.com/g' /etc/apt/sources.list && \
    sed -i 's/security.ubuntu.com/mirrors.aliyun.com/g' /etc/apt/sources.list

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

docker build -f dockerfile.cmd -t ipinfo .

image-20250104162121567

 docker container run -it ipinfo

随后启动容器,发现已经进入ubuntu shell中,这是因为ubuntu的基础镜像中有自定义的CMD

docker image history ipinfo

image-20250104162311365

如果启动容器时指定了其他命令,cmd会被忽略。

# 追加ipinfo命令
docker container run -it ipinfo ipinfo

image-20250104162728387

如果容器中包含多个CMD命令

FROM ubuntu:20.04
ENV VERSION=2.0.1
RUN sed -i 's/archive.ubuntu.com/mirrors.aliyun.com/g' /etc/apt/sources.list && \
    sed -i 's/security.ubuntu.com/mirrors.aliyun.com/g' /etc/apt/sources.list

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 ["ipinfo"]

此时,既有ubuntu默认的cmd也有制定的cmd。

docker build -f dockerfile.cmd -t ipinfo-new .

image-20250104163252970

docker container run -it ipinfo-new

进入容器,发现执行的CMD为ipinfo,即如果dockerfile中指定了CMD,优先执行。

针对一次性执行的容器,可以在创建时带上-rm命令,创建运行完成后即删除。

docker container run --rm -it ipinfo ipinfo 8.8.8.8

容器启动命令ENTRYPOINT

ENTRYPOINT也可以设置启动时要执行的命令,但是和CMD是有区别的。

  • CMD设置的命令,可以在docker container run时传入其他命令,覆盖掉CMD的命令,但是ENTRYPOINT所设置的命令是一定会被执行的。
  • ENTRYPOINTCMD可以联合使用,ENTRYPOINT设置执行的命令,CMD传递参数。

使用CMD命令

FROM ubuntu:20.04
CMD ["echo", "hello docker"]

使用ENTRYPOINT命令

FROM ubuntu:20.04
ENTRYPOINT ["echo", "hello docker"]

Both

FROM ubuntu:20.04
ENTRYPOINT ["echo"]
CMD []
# 构件cmd镜像
docker build -f dockerfile-cmd -t demo-cmd .

运行demo-cmd镜像

docker container run --rm -it demo-cmd

结果输出“hello docker”

使用命令追加在container命令后,执行追加的命令,会覆盖dockerfile中的cmd。

docker container run --rm -it demo-cmd echo "hello world"

结果输出“hello world”

image-20250104170732323

# 构件entrypoint
docker container run --rm -it demo-entrypoint

结果输出“hello docker”

docker container run --rm -it demo-entrypoint echo "hello world"

结果输出“hello docker echo hello world”,原因是在ENTRYPOINT中设置的echo命令是一定会被执行的。

# 构建both
docker container run --rm -it demo-both

结果打印为空

# 追加cmd
docker container run --rm -it demo-both hello world

image-20250104171507337

Shell格式和Exec格式

CMD和ENTRYPOINT同时支持shell和exec格式。

注意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"]

练习

编写Tomcat DockerFile

FROM centos
MAINTAINER zhang<xxxxx@qq.com>

ADD jdk-8u11-linux-x64.tar.gz /usr/local
ADD apache-tomcat-9.0.98.tar.gz /usr/local

RUN yum -y install vim 

ENV MYPATH=/usr/local

WORKDIR $MYPATH

ENV JAVA_HOME /usr/local/jdk1.8.0_11
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:${JAVA_HOME}/lib/tools.jar

ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.98
ENV CATALINA_BASE /usr/local/apache-tomcat-9.0.98
ENV PATH $PATH:$JAVA_HOME/bin:${CATALINA_HOME}/bin:${CATALINA_HOME}/lib

EXPOSE 8080


CMD /usr/local/apache-tomcat-9.0.98/bin/startup.sh && tail -f /usr/local/apache-tomcat-9.0.98/logs/catalina.out

构件镜像

docker build -t diy_tomcat .

启动镜像

docker run -d -p 9090:8080 --name diy_tomcat -v /root/tomcat/test:/usr/local/apache-tomcat-9.0.98/webapps/test -v /root/tomcat/logs/:/usr/local/apache-tomcat-9.0.98/logs diytomcat

查看运行状态

docker ps -a

浏览器可正常访问tomcat首页

image-20250104200214506

随后在/root/tomcat/test下编辑index.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>我的复杂网页</title>
  <link rel="stylesheet" href="styles.css">
</head>

<body>
  <!-- 这里将是网页内容的主要部分 -->
  <h3>hello docker</h3>

</body>

查看/test路径

image-20250104200422513

全貌

posted @   shine-rainbow  阅读(131)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
点击右上角即可分享
微信分享提示