Docker 06 Dockerfile

一、什么是Dockerfile

Docker为我们提供的一个用于自定义构建镜像的一个配置文件:描述如何构建一个对象。利用docker提供的build命令,指定Dockerfile文件,就可以安装配置的内容将镜像构建出来

二、为什么要自己构建呢?

  1. 作为开发者,需要将自己开发好的项目打包成Docker镜像,便于后面直接为Docker容器运行
  2. 作为运维,需要构建更精简的基础设施服务镜像,满足公司的需求以及尽可能减少冗余的功能占用过多的资源。

三、能做什么?

  1. 自定义镜像内容
  2. 构建公共基础镜像减少其他镜像配置
  3. 开源程序的快速部署
  4. 实现企业内部项目的快速交付

四、构建镜像指令

commit

build

五、构建镜像方式 1:commit

基于一个现有的容器,构建一个新的镜像

build是通过一个dockerfile配置好一个文件,基于这个文件可以多次操作;而commit相当于一次性的操作。我做了一次变动,变动了之后基于这个容器直接构建出来,这个变动就完成了,
不可能在基于这个变动去重复的执行。commit前提是必须有一个容器。

命令:
docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]

例:
docker commit -a="wolfcode" -m="first image" centos7 mycentos:7

OPTIONS:
-a:镜像的作者
-c:使用Dockerfile指令来构建镜像
-m: 提交时的描述
-p: 在commit时暂停容器

# 1. 启动nginx容器实例
docker run --rm -d -p 8765:80 --name nginx_commit nginx

# 2. 进入到nginx容器实例的shell中
docker exec -it nginx_commit /bin/bash

# 3. 自定义nginx主页内容
cd /usr/share/nginx/html
echo '<h1>Welcome My Nginx</h1>' > index.html

# 4. 退出容器shell
exit

# 5. 以Birkhoff作者名,基于上面启动的nginx_commit名称的容器创建 自己的镜像:mynginx,版本是1 
docker commit -a "Birkhoff" -m "my nginx container" nginx_commit mynginx:1

# 6. 查看镜像
docker image

# 7. 运行自定义镜像实例
docker run --rm -d -p 8766:80 --name my_own_nginx mynginx:1

六、构建镜像方式 2:build

常用指令

  1. FROM
  2. MAINTAINER
  3. LABEL
  4. RUN
  5. ADD
  6. WORKDIR
  7. VOLUME
  8. EXPOSE
  9. CMD
  10. ENTRYPOINT

拓展指令

  1. USER
  2. ARG
  3. ONBUILD
  4. STOPSIGNAL
  5. HEALTHCHECK

七、dockerfile 指令简要概述

  1. FROM: 先指定当前镜像的基础镜像是什么
    FROM openjdk:8
    (可以通过docker search 或者直接去 docker hub网站查询)

  2. MAINTAINER: 描述这个镜像的作者,以及联系方式(可选)
    MAINTAINER Birkhoff<Birkhoff@shadownet.com>
    (作为开源爱好者,作者分享我的开源软件的时候,一般会加➕️)

  3. LEBEL: 镜像的标签信息(可选)
    LABEL version="1.8"
    LABEL description="这是我的第一个Dockerfile"

  4. ENV: 环境变量配置
    ENV JAVA_ENV dev
    ENV APP_NAME test-dockerfile
    或
    ENV JAVA_ENV=DEV APP_NAME=test-dockerfile

  5. RUN:在构建镜像时需要执行的 shell 命令
    RUN ls -al
    RUN mkdir /www/dockerfile/test

  6. ADD: 将主机中的指定文件复制到容器的目标位置,可以简单理解为cp命令
    ADD /etc/hosts /etc/hosts
    = ADD ["/etc/hosts", "/etc/hosts"]
    |
    ADD /www/wolfcode.cn/index.html /www/server
    = ADD ["/www/wolfcode.cn/index.html", "/www/server"]

  7. WORKDIR: 设置并进入容器中的工作目录(cd),如果目录不存在则自动创建(等同linux的mkdir)
    WORKDIR /app
    //在设置完工作目录后,执行pwd命令,打印的目录就是 /app
    RUN pwd

  8. VOLUME: 镜像数据卷绑定,将主机中的指定目录挂载到容器中
    VOLUME ["/www/wolfcode.cn"]
    在主机中有 /www/wolfcode.cn, 容器中也有 /www/wolfcode.cn, 且会互相同步

  9. EXPOSE: 设置容器启动后要暴露的端口
    EXPOSE 8080/tcp

  10. CMD: 启动容器时默认执行的脚本
    CMD ping 127.0.0.1
    CMD ["sh", "-c", "ping 127.0.0.1" ]

  11. ENTRYPOINT: 启动容器时默认执行的脚本
    ENTRYPOINT ping 127.0.0.1
    ENTRYPOINT ["sh", "-c", "ping 127.0.0.1" ]
    CMD 和 ENTRYPOINT 选择其一即可,作用是描述构建镜像完成后,启动容器时默认执行的脚本

  12. ARG

ARG jdk=8
FROM openjdk:$jdk

docker build -t --build-arg jdk=11 (构建镜像时动态指定)
  1. USER
    //拓展:表示后续容器中所有执行 命令的操作都是以wolfcode这个用户操作的
    USER wolfcode

  2. 拓展:

健康检查,每隔10s检查容器是否正常,每次不超过3s,并且失败了,最多不能超过3次
HEALTHCHECK --internal=10 --timeout=3 --retries=5 CMD ps -ef | grep java || exit 1


八、Dockerfile指令详情

1. FROM

指定以什么镜像作为基础镜像,在改进项的基础之上构建新的镜象。
如果不想以任何镜像作为基础: FROM scratch

语法:
FROM <image>
FROM <image>:<tag>
FROM <image>:<digest>

以上为三种写法,后两者为指定具体版本,第一种则使用latest,也就是最新版


2. MAINTAINER

作者


3. LABEL

为镜像设置标签,一个Dockerfile中可以配置多个LABEL

语法:
LABEL <key>=<value>

如:
LABEL "example.label"="Example Label"
LABEL label-value="LABEL"
LABEL version="1.0.0"
LABELdescription="可以写成多行,使用
符号可以拼接多行的value"


4. ENV

设置容器的环境变量,可以设置多个

语法:
ENV <key> <value>个
ENY <key>=<value> <key>=<value>...

两种语法的区别为第一种一次只能设置一个环境变量,第二种可以一次设置多个


5. RUN

构建镜像的过程中要执行的命令

语法:
RUN <command>
RUN ["executable","param1","param2","paramN"]

第一种写法就是直接写 Shell脚本即可
第二种写法类似函数调用,第一个参数为可执行文件,后面的都是参数


6. ADD

复制命令,把src的文件复制到镜像的dest位置

语法:
ADD <src> <dest>
ADD ["<src>","<dest>"]


7. WROKDIR

若有目录:cd 目录
若没目录:mkdir 目录 + cd 目录


8. VOLUME

设置挂载目录,可以将主机中的指定目录挂载到容器中

语法:
VOLUME ["<dir>"]
VOLUME <dir>
VOLUME <dir> <dir>
以上三种写法都可


9. EXPOSE

该镜像运行容器后,需要暴露给外部的端口,但仅仅表示该容器想要暴露某些端口,并不会与主机端口有映射关系,如果想将容器暴露的端口与主机映射则需要使用-p或-P参数来映射,可以暴露多个端口

语法:
EXPOSE <port>/<tcp/udp>


10. CMD

该镜像启动容器时默认执行的命令或参数

语法:
CMD ["param1", "param2"]
CMD ["executable", "param1", "param2"]
CMD <command> <param1> <param2>
以上为该命令的三种写法,第三种与普通Shell命令类似,第一、二两种都是可执行文件+参数的形式,另外数组内的参数必须使用双引号。

案例:


11. ENTRYPOINT

运行容器时的启动命令,感觉与CMD命令会很像,实际上还是有很大区别,简单对比一下:

语法:
ENTRYPOINT ["executable", "param1", "param2"]
ENTRYPOINT command param1 param2

与CMD相同点:
在整个Dockerfile中只能设置一次,如果写了多次则只有最后一次生效

与CMD不同点:

  1. ENTRYPQINT不会被运行容器时指定的命令所覆盖,而CMD会被覆盖
  2. 如果同时设置了这两个指令,且CMD仅仅是选项而不是参数,CMD中的内容会作为ENTRYPOINI的参数(一般不这么做)
  3. 如果两个都是完整命令,那么只会执行最后一条

拓展指令

12. ARG

设置变量,在镜像中(构建Dockerfile时)定义一个变量,当使用docker build命令构建镜像时,带上--build-arg=来指定参数值,如果该变量名在Dockerfile中不存在则会抛出一个警告

语法:
ARG <name>[=<default value>]


13. USER

设置容器的用户,可以是用户名或UID,如果容器设置了以daemon用户去运行,那么RUN、CMD和ENTRYPOINT都会以这个用户去运行,一定要先确定容器中有这个用户,并且拥有对应的操作权限。

语法:
USER <username>
USER <PID>


14. ONBUILD

表示在构建镜像时做某操作,不过不对当前Dockerfile的镜像生效,而是对以当前Dockerfile镜像作为基础镜像的子镜像生效

语法:
ONBUILD [INSTRUCTION]

例:

当前镜像为A,设置了如下指令
ONBUILD RUN ls -al

镜像B:
FROM 镜像A
......
构建镜像B时,会执行ls -al命令

15. STOPSIGNAL

  1. STQPSIGNAL指令设置将发送到容器的系统调用信号以退出。此信号可以是与内核的系统调用表中的位置匹配的有效无符号数,例如9,或SIGNAME格式的信号名,例如SIGKILL。
  2. 默认的stop-signal是SIGTERM,在docker stop的时候会给容器内PID为1的进程发送这个signal,通过--stop-signal可以设置自己需要的signal,主要的目的是为了让容器内的应用程序在接收到signal之后可以先做一些事情,实现容器的平滑退出,如果不做任何处理,容器将在一段时间之后强制退出,会造成业务的强制中断,这个时间默认是10s。
    STOPSIGNAL

16. HEALCHECK

容器健康状况检查,可以指定周期检查容器当前的健康状况,该命令只能出现一次,如果有多次则只有最后一次生效。

语法:
HEALTHCHECK [OPTONS] CMD command
HEALTHCHECK NONE

第一种: 在容器内部按照指定周期运行指定命令来检测容器健康状况
第二种: 取消在基础镜像

OPTIONS选项:
--interval=DURATION 两次检查的间隔时间,默认30s
--timeout=DURATION 命令执行的超时时间,默认30s
--retries=N 当连续失败指定次数,容器会被认定为不健康,默认为3次

返回参数:

  • 0 : success=>健康状态
  • 1 : unhealthy =>不健康状态
  • 2 : reserved=>保留值

九、SpringBoot项目

  1. 在jar包同目录下,创建 Dockerfile文件
  2. 编写Dockerfiele文件
# 关联基础镜像 jdk
FROM openjdk:8

# 将项目Jar包拷贝到容器中
ADD *.jar app.jar

# 配置目标环境变量
ENV APP_OPTS=""
# JVM 环境变量
ENV JVM_OPTS="-Duser.timezone=Asia/Shanghai -Xms128m -Xmx128m"

# 暴露端口
EXPOSE 8888

# 设置启动时命令
ENTRYPOINT ["sh" , "-c", "java $JVM_OPTS -jar /app.jar $APP_OPTS"]

//最后面的点代表当前文件
3. docker build -t sprintboot-demo-docker:1.0.0 .

  1. docker images

  2. docker run --rm -d -P springboot-demo-docker:1.0.0

  3. docker ps


十、tomcat 镜像构建

/opt/dockerfiles/javaweb-docker-demo/Dockerfile 文件:

FROM tomcat9.0

WORKDIR /user/local/tomcat/webapps

ADD xxxx.war ROOT.war

# 后端允许,容器不能被卡住,容器不能持续的允许起来
# ENTRYPOINT ["sh", "-c", "../bin/startup.sh"]
ENTRYPOINT ["sh", "-c", "../bin/catalina.sh run"]

docker build -t javaweb /opt/dockerfiles/javaweb-docker-demo
docker images
docker run --rm -d -P javaweb
docker ps


十一、源码构建Nginx服务

  1. 下载最新Nginx 服务源码包
    wget https://nginx.org/download/nginx-1.30.5.tar.gz

//pcre-8.45.tar.gz 是一款面向 Linux 系统的正则表达式库资源文件
pcre-8.45.tar.gz

  1. 编写Dockerfile
# 设置基础镜像
FROM centos

# 维护信息
MAINTAINER Birkhoff<birkhoff@163.com>

# 加入构建镜像所需要的文件, ADD 命令会帮助压缩包解压
ADD pcre-8.45.tar.gz /usr/local/src
ADD nginx-1.30.5.tar.gz /usr/local/src

# 1. 备份并清理旧的 repo 文件,避免干扰
RUN mkdir -p /etc/yum.repos.d/backup && \
    mv /etc/yum.repos.d/CentOS-*.repo /etc/yum.repos.d/backup/ 2>/dev/null || true

# 2. 下载阿里云的 CentOS 8 Vault 源配置文件
RUN curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-vault-8.5.2111.repo

# 3. 清理并重建 YUM 缓存
RUN yum clean all && yum makecache

# 下载按照一些基础工具
# 安装C++源码编译的基础工具
RUN yum install -y wget gcc gcc-c++ make openssl openssl-devel zlib zlib-devel libtool

# 创建www用户做为nginx启动用户, 用户不能登录
RUN useradd -s /sbin/nologin -M www

#进入nginx解压后的源码目录,进行编译安装操作
WORKDIR /usr/local/src/nginx-1.30.5

# nginx编译安装
RUN ./configure --prefix=/usr/local/nginx --user=www --group=www --with-http_ssl_module --with-http_stub_status_module --with-pcre=/usr/local/src/pcre-8.45
RUN make && make install

# 注意,nginx服务默认是在后台运行的,那么就没有一个东西能挂住我们的容器,不能卡住容器,让容器持续运行。
# 所以,需要将nginx后台运行关掉
RUN echo 'daemon off;' >> /usr/local/nginx/conf/nginx.conf

# 设置nginx命令快速访问的环境变量
ENV PATH /usr/local/nginx/sbin:$PATH

# 或者软链接的方式设置nginx启动命令为系统命令
#ls -s /usr/local/nginx/sbin/nginx /usr/local/bin/nginx

# 暴露端口
EXPOSE 80

# 容器启动命令
CMD ["nginx"]

构建Dockerfile

docker build -t docker_nginx .
docker images
docker run --rm -d  -P docker_nginx
docker ps

# 端口号没有映射(因为没有Dockerfile没有暴露端口)
CONTAINER ID   IMAGE          COMMAND   CREATED         STATUS         PORTS     NAMES
c3cef03e1f73   dockre_nginx   "nginx"   6 seconds ago   Up 5 seconds             nice_heisenberg
posted @ 2026-09-16 11:25  超轶绝尘  阅读(8)  评论(0)    收藏  举报