Docker 06 Dockerfile
一、什么是Dockerfile
Docker为我们提供的一个用于自定义构建镜像的一个配置文件:描述如何构建一个对象。利用docker提供的build命令,指定Dockerfile文件,就可以安装配置的内容将镜像构建出来
二、为什么要自己构建呢?
- 作为开发者,需要将自己开发好的项目打包成Docker镜像,便于后面直接为Docker容器运行
- 作为运维,需要构建更精简的基础设施服务镜像,满足公司的需求以及尽可能减少冗余的功能占用过多的资源。
三、能做什么?
- 自定义镜像内容
- 构建公共基础镜像减少其他镜像配置
- 开源程序的快速部署
- 实现企业内部项目的快速交付
四、构建镜像指令
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
常用指令
- FROM
- MAINTAINER
- LABEL
- RUN
- ADD
- WORKDIR
- VOLUME
- EXPOSE
- CMD
- ENTRYPOINT
拓展指令
- USER
- ARG
- ONBUILD
- STOPSIGNAL
- HEALTHCHECK
七、dockerfile 指令简要概述
-
FROM: 先指定当前镜像的基础镜像是什么
FROM openjdk:8
(可以通过docker search 或者直接去 docker hub网站查询) -
MAINTAINER: 描述这个镜像的作者,以及联系方式(可选)
MAINTAINER Birkhoff<Birkhoff@shadownet.com>
(作为开源爱好者,作者分享我的开源软件的时候,一般会加➕️) -
LEBEL: 镜像的标签信息(可选)
LABEL version="1.8"
LABEL description="这是我的第一个Dockerfile" -
ENV: 环境变量配置
ENV JAVA_ENV dev
ENV APP_NAME test-dockerfile
或
ENV JAVA_ENV=DEV APP_NAME=test-dockerfile -
RUN:在构建镜像时需要执行的 shell 命令
RUN ls -al
RUN mkdir /www/dockerfile/test -
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"] -
WORKDIR: 设置并进入容器中的工作目录(cd),如果目录不存在则自动创建(等同linux的mkdir)
WORKDIR /app
//在设置完工作目录后,执行pwd命令,打印的目录就是 /app
RUN pwd -
VOLUME: 镜像数据卷绑定,将主机中的指定目录挂载到容器中
VOLUME ["/www/wolfcode.cn"]
在主机中有 /www/wolfcode.cn, 容器中也有 /www/wolfcode.cn, 且会互相同步 -
EXPOSE: 设置容器启动后要暴露的端口
EXPOSE 8080/tcp -
CMD: 启动容器时默认执行的脚本
CMD ping 127.0.0.1
CMD ["sh", "-c", "ping 127.0.0.1" ] -
ENTRYPOINT: 启动容器时默认执行的脚本
ENTRYPOINT ping 127.0.0.1
ENTRYPOINT ["sh", "-c", "ping 127.0.0.1" ]
CMD 和 ENTRYPOINT 选择其一即可,作用是描述构建镜像完成后,启动容器时默认执行的脚本 -
ARG
ARG jdk=8
FROM openjdk:$jdk
docker build -t --build-arg jdk=11 (构建镜像时动态指定)
-
USER
//拓展:表示后续容器中所有执行 命令的操作都是以wolfcode这个用户操作的
USER wolfcode -
拓展:
健康检查,每隔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不同点:
- ENTRYPQINT不会被运行容器时指定的命令所覆盖,而CMD会被覆盖
- 如果同时设置了这两个指令,且CMD仅仅是选项而不是参数,CMD中的内容会作为ENTRYPOINI的参数(一般不这么做)
- 如果两个都是完整命令,那么只会执行最后一条
拓展指令
12. ARG
设置变量,在镜像中(构建Dockerfile时)定义一个变量,当使用docker build命令构建镜像时,带上--build-arg
语法:
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
- STQPSIGNAL指令设置将发送到容器的系统调用信号以退出。此信号可以是与内核的系统调用表中的位置匹配的有效无符号数,例如9,或SIGNAME格式的信号名,例如SIGKILL。
- 默认的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项目
- 在jar包同目录下,创建 Dockerfile文件
- 编写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 .
-
docker images
-
docker run --rm -d -P springboot-demo-docker:1.0.0
-
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服务
- 下载最新Nginx 服务源码包
wget https://nginx.org/download/nginx-1.30.5.tar.gz
//pcre-8.45.tar.gz 是一款面向 Linux 系统的正则表达式库资源文件
pcre-8.45.tar.gz
- 编写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

浙公网安备 33010602011771号