Dockerfile介绍
Dockerfile类似于shell的脚本,由一条条指令组成,Docker进程可以通过读取Dockerfile中的指令,依据指令内容自动构建生成镜像。
Dockerfile常用指令
FROM
LABEL
RUN
EXPOSE
COPY
ADD
ENV
ARG
USER
CMD
ENTRYPOINT
VOLUME
WORKDIR
FROM: 指定基础镜像
FROM指令:指定dockerfile的底层镜像,后续都每条指令都可以看做是在这个底层镜像上的叠加,Dockerfile一般都是以FROM指令开头,其镜像文件,一般选用官方提供的镜像较为安全,当然也可以是已经制作好的本地镜像。
FROM [--platform=<platform>] <image> [AS <name>]
FROM [--platform=<platform>] <image>[:<tag>] [AS <name>]
FROM [--platform=<platform>] <image>[@<digest>] [AS <name>]
--platform 指定镜像的平台,比如: linux/amd64, linux/arm64, or windows/amd64 tag 和 digest是可选项,如果不指定,默认为latest
# 示例
FROM scratch #所有镜像的起源镜像
FROM ubuntu
FROM ubuntu:bionic
FROM centos:7.9.2009
LABEL: 指定镜像元数据
LABEL指令:向镜像中添加元数据信息,例如 镜像的作者,镜像的信息,镜像的版本号,它是以键值对的方式来存储数据的,一个镜像可以有多个LABEL,可以写在一行中,也可以写在多行中,行尾使用 号分隔,推荐写在一行中,可以减少镜像的大小。
LABEL <key>=<value> <key>=<value> <key>=<value> ...
# 示例
#一行格式
LABEL label1="value1" label2="value2" label3="value3"
#多行格式
LABEL label1="value1"
label2="value2"
label3="value3"
RUN: 执行 shell 命令
RUN指令:在当前映像的顶部执行shell命令,并提交生成一层镜像,每一个RUN指令都会建立一个镜像层,所以尽可能将多个RUN合并成一条指令,以减少镜像层数,比如将多个shell命令通过 && 连接一起成为在一条指令。
# RUN指令后面直接跟shell命令,默认为sh -c
RUN <命令>
# exec格式
RUN ["executable", "param1", "param2"] (exec form)
# exec格式只支持双引号,不支持单引号,也无法使用环境变量,但它可以指定其它shell。例如:
RUN ["/bin/bash","-c","echo hello,world!"]
# 示例
RUN echo 'Welcome to Nginx in Docker !' > /usr/share/nginx/html/index.html
RUN yum -y install epel-release
&& yum -y install nginx
&& rm -rf /usr/share/nginx/html/*
&& echo 'Welcome to Nginx in Docker !' > /usr/share/nginx/html/index.html
注意事项:
- 每条RUN命令的初始目录都是基于WOKRDIR目录,并不会因为上一条RUN命令进入了某个目录而影响后续的RUN命令的初始目录。
EXPOSE:暴露端口
EXPOSE指令:指定服务端容器打算监听的端口号,但实际上并不会主动发布端口,仅仅只是声明,只有在启动容器的时候通过-P或者-p参数,Docker才会真正将端口暴露出来使用。
EXPOSE <port> [<port>/<protocol>...]
# 示例
EXPOSE 80 443
EXPOSE 80/tcp
EXPOSE 80/udp
注意事项:
- 默认情况下,EXPOSE使用TCP,当然也可以指定为UDP。
- 即使Dockerfile文件中没有使用EXPOSE指令指定暴露端口,也可以在启动容器的时候通过-p参数来暴露指定的监听端口,所以,EXPOSE指令仅用于指定默认的暴露端口,通过-P参数才能进行真正的端口暴露。
COPY:复制文件
COPY指令:可以复制宿主机中的文件到容器中 ,并且连元数据等相关信息也一起复制,如读写执行权限,文件创建变更时间,但如果没有--chown指定属主,默认属主为容器root用户。
# COPY指令有两种使用方式,如果路径中包含空格,需要使用第二种格式
COPY [--chown=<user>:<group>] <src>... <dest>
COPY [--chown=<user>:<group>] ["<src>",... "<dest>"]
注意事项:
- 可以指定多个
,支持通配符,使用 Go’s filepath.Match rules。 - 如果
是目录,则将复制目录的整个内容,但目录本身不会被复制。 基于当前Dockerfile的相对路径。 是绝对路径或相对于WORKDIR的路径。 - 如果
不是以斜杠/结束,它将被认为是 源文件拷贝后的重命名文件,如果以结尾斜杠/结束,它将被视为目录,即将 源文件拷贝到 目录下。 - 当指定了多个
,或者使用了通配符的情况下, 必须以/结尾。 - --chown只支持linux系统。
- 如果 < dest > 不存在,则递归创建所有不存在的目录。
ADD:复制和解压文件
ADD指令:该指令不仅支持复制文件,如果复制的文件是一个压缩文件,还支持自动解压缩。另外还支持URL下载,下载后的文件权限默认为600。
# 和COPY指令类似,有两种使用方式,如果路径中包含空格,需要使用第二种格式
ADD [--chown=<user>:<group>] <src>... <dest>
ADD [--chown=<user>:<group>] ["<src>",... "<dest>"]
注意事项:
- 参考COPY指令的注意事项 ,ADD指令基本都适用。
- 如果URL是一个tar.gz类的压缩文件,下载后并不会自动解压。
ENV: 设置环境变量
ENV指令:用来定义环境变量。可以被所有后续指令(如:ENV,ADD,COPY,RUN等)进行引用,
并在容器运行时保持此值。
# 只能对一个key赋值,<key>之后的所有内容均会被视作其<value>的组成部分
ENV <key> <value>
# 支持多个key赋值,定义多个变量建议使用,减少镜像层
ENV <key1>=<value1> <key2>=<value2>
<key3>=<value3> ...
#如果<value>中包含空格,可以以反斜线进行转义,也可通过对<value>加引号进行标识;另外,反斜线也可用于续行
# 如果只在构筑镜像的时候使用一次变量,可以考虑在RUN命令中直接设置
RUN <key>=<value> <command>
#引用变量
RUN $key .....
#变量支持高级赋值格式
${key:-word}
${kye:+word}
ARG: 构建参数
ARG指令:在镜像构建阶段指定变量,和ENV不同的是,容器运行后并不会保留变量。也可以在构建镜像时使用docker build命令的--build-arg
ARG <name>[=<default value>]
# 示例
FROM centos:7.9.2009
RUN touch ${test:-aaa}.txt
ARG test=demo
RUN touch ${test:-bbb}.txt
# 上面示例最终会生成一个aaa.txt文件和demo.txt文件
[root@ubuntu2004:/docker/test]# docker run -it --name t4 fbf6635fb360 bash
[root@0c5878a01837 /]# ls
aaa.txt bin dev home lib64 mnt proc run srv tmp var
anaconda-post.log demo.txt etc lib media opt root sbin sys usr
注意事项:
- 如果同时存在同名的ENV和ARG变量,ENV变量将覆盖ARG变量。
- ARG变量定义从Dockerfile中定义的行往后才开始生效。
- 不建议在构建镜像时使用-build-arg参数来传递如密钥,用户凭据等信息,因为使用docker history命令可以看得到。
USER:指定用户
USER指令:用于指定运行容器时的用户名或者UID。
USER <user>[:<group>]
USER <UID>[:<GID>]
# 示例
RUN groupadd -r test
&& useradd -r -g test test
USER test
注意事项:
- 用户必须提前创建好,否则会报错。
- 如果没有指定用户,默认使用root身份运行容器。
- Dockerfile后续的指令例如RUN,CMD,ENTRYPOINT也会使用该指定用户。
CMD:容器运行命令
CMD指令:用来指定在启动容器时默认执行的命令,该命令运行结束后,容器将停止运行,所以一般情况下CMD均为可持续运行的前台命令。使用docker run运行容器的时候可以后续指定具体命令来覆盖CMD中的命令。
# exec格式,不支持环境变量,第一个参数必须为绝对路径
CMD ["executable","param1","param2"]
# 用于给ENTRYPOINT传递参数
CMD ["param1","param2"]
# 之间跟shell命令和参数,支持环境变量,默认使用/bin/sh
CMD command param1 param2
# 示例
CMD ["nginx","-g","demon off;"]
注意事项:
- Dockerfile中只能有一个CMD命令,如果有多个,只有最后一条会生效。
- 当Dockerfile中同时还有ENTRYPOINT指令时,CMD只能当做其参数使用。
ENTRYPOINT:入口点
ENTRYPOINT指令:该指令功能类似于CMD指令,所不同的是ENTRYPOINT指令中的命令不能被docker run后续的命令所覆盖,而是将其追加作为参数使用。
如果想要覆盖Dockerfile中的ENTRYPOINT指令,可以在docker run后使用--entrypoint参数来指令新的命令作为入口点。
ENTRYPOINT指令可以结合exec命令,在启动容器的时候运行脚本。
# exec格式
ENTRYPOINT ["executable", "param1", "param2"]
# shell格式
ENTRYPOINT command param1 param2
VOLUME:匿名卷
VOLUME指令:用于为容器中的某个目录创建一个挂载点来存放需要保存的数据,即使容器被删除后,该目录对应的宿主机目录也会一直存在,宿主机目录的默认路径为 /var/lib/docker/volumes/<volume_id>/_data ,因为是匿名卷,不太好查找,可以使用docker inspect <image_id>l来查看具体的目录信息。
我们在使用docker run命令启动容器的时候可以使用 -v 参数来指定具体的目录挂载关系,因此该指令也不算太常用,当然,用户在使用docker run命令启动容器的时候可能会忘记使用 -v 参数指定挂载点,因此对于有重要数据的容器来说,VOLUME指令相当于多了一层保障。
VOLUME ["/data"]
VOLUME ["/data1","/data2"]
WORKDIR:工作目录
WORKDIR指令:该指令可以为后续的RUN,CMD,ENTRYPOINT,COPY和ADD指令配置默认的工作目录,当容器运行后,也会进入WORKDIR所指定的目录。
WORKDIR /path/to/workdir
使用docker build命令构建镜像
查看帮助:
[root@ubuntu2004:~]# docker build --help
Usage: docker build [OPTIONS] PATH | URL | -
Build an image from a Dockerfile
Options:
--add-host list Add a custom host-to-IP mapping (host:ip)
--build-arg list Set build-time variables
--cache-from strings Images to consider as cache sources
--cgroup-parent string Optional parent cgroup for the container
--compress Compress the build context using gzip
--cpu-period int Limit the CPU CFS (Completely Fair Scheduler) period
--cpu-quota int Limit the CPU CFS (Completely Fair Scheduler) quota
-c, --cpu-shares int CPU shares (relative weight)
--cpuset-cpus string CPUs in which to allow execution (0-3, 0,1)
--cpuset-mems string MEMs in which to allow execution (0-3, 0,1)
--disable-content-trust Skip image verification (default true)
-f, --file string Name of the Dockerfile (Default is 'PATH/Dockerfile')
--force-rm Always remove intermediate containers
--iidfile string Write the image ID to the file
--isolation string Container isolation technology
--label list Set metadata for an image
-m, --memory bytes Memory limit
--memory-swap bytes Swap limit equal to memory plus swap: '-1' to
enable unlimited swap
--network string Set the networking mode for the RUN instructions
during build (default "default")
--no-cache Do not use cache when building the image
-o, --output stringArray Output destination (format: type=local,dest=path)
--platform string Set platform if server is multi-platform capable
--progress string Set type of progress output (auto, plain, tty).
Use plain to show container output (default "auto")
--pull Always attempt to pull a newer version of the image
-q, --quiet Suppress the build output and print image ID on success
--rm Remove intermediate containers after a successful
build (default true)
--secret stringArray Secret file to expose to the build (only if
BuildKit enabled): id=mysecret,src=/local/secret
--security-opt strings Security options
--shm-size bytes Size of /dev/shm
--squash Squash newly built layers into a single new layer
--ssh stringArray SSH agent socket or keys to expose to the build
(only if BuildKit enabled) (format:
default|<id>[=<socket>|<key>[,<key>]])
--stream Stream attaches to server to negotiate build context
-t, --tag list Name and optionally a tag in the 'name:tag' format
--target string Set the target build stage to build.
--ulimit ulimit Ulimit options (default [])
示例:
[root@ubuntu2004:~]# docker build -t cenos7.9:base-v1.0 .
范例:Tomcat业务镜像制作
1. 制作 CentOS 基础镜像
[root@ubuntu2004:/docker/centos]# ls
CentOS7.repo Dockerfile
[root@ubuntu2004:/docker/centos]# cat CentOS7.repo
[Base-Package]
name=Base
baseurl=http://mirrors.tuna.tsinghua.edu.cn/centos/7/os/x86_64/
http://mirrors.aliyun.com/centos/7/os/x86_64/
http://mirrors.huaweicloud.com/centos/7/os/x86_64/
gpgcheck=1
gpgkey=http://mirrors.tuna.tsinghua.edu.cn/centos/7/os/x86_64/RPM-GPG-KEY-CentOS-7
[Epel]
name=epel
baseurl=http://mirrors.tuna.tsinghua.edu.cn/epel/7/x86_64/
http://mirrors.aliyun.com/epel/7/x86_64/
http://mirrors.huaweicloud.com/epel/7/x86_64/
gpgcheck=1
gpgkey=http://mirrors.tuna.tsinghua.edu.cn/epel/RPM-GPG-KEY-EPEL-7
[Extras]
name=extras
baseurl=http://mirrors.tuna.tsinghua.edu.cn/centos/7/extras/x86_64/
http://mirrors.aliyun.com/centos/7/extras/x86_64/
http://mirrors.huaweicloud.com/centos/7/extras/x86_64/
gpgcheck=1
gpgkey=http://mirrors.tuna.tsinghua.edu.cn/centos/RPM-GPG-KEY-CentOS-Official
[root@ubuntu2004:/docker/centos]# cat Dockerfile
FROM centos:7.9.2009
LABEL maintainer=wuvikr message=centos7.9_base_image
COPY CentOS7.repo /etc/yum.repos.d/
RUN find /etc/yum.repos.d ! -name CentOS7.repo -a -type f -exec rm -rf {} ;
&& yum -y install vim curl wget telnet tree wget bash-completion net-tools iproute lrzsz lsof zip unzip nfs-utils gcc make glibc glibc-devel pcre pcre-devel openssl openssl-devel systemd-devel zlib-devel rsync tcpdump psmisc bzip2
&& yum clean all
&& rm -f /etc/localtime
&& ln -s ../usr/share/zoneinfo/Asia/Shanghai /etc/localtime
RUN groupadd www -g 2020 && useradd www -u 2020 -g www
[root@ubuntu2004:/docker/centos]# docker build -t centos7.9:base .
2. 制作构建 JDK 镜像
[root@ubuntu2004:/docker/jdk]# ls
Dockerfile jdk-8u271-linux-x64.tar.gz jdk.sh
[root@ubuntu2004:/docker/jdk]# cat jdk.sh
export JAVA_HOME=/usr/local/jdk
export PATH=$JAVA_HOME/bin:$PATH
export JRE_HOME=$JAVA_HOME/jre
export CLASSPATH=$JAVA_HOME/lib/:$JRE_HOME/lib/
[root@ubuntu2004:/docker/jdk]# cat Dockerfile
FROM centos7.9:base
LABEL maintainer=wuvikr message=JDK8u271-CentOS7.9
ADD jdk-8u271-linux-x64.tar.gz /usr/local/src/
RUN ln -s /usr/local/src/jdk1.8.0_271 /usr/local/jdk
COPY jdk.sh /etc/profile.d/
ENV JAVA_HOME="/usr/local/jdk" PATH="${JAVA_HOME}/bin:${PATH}"
JRE_HOME="${JAVA_HOME}/jre" CLASSPATH="${JAVA_HOME}/lib/:${JRE_HOME}/lib/"
[root@ubuntu2004:/docker/jdk]# docker build -t centos7.9-jdk:8u271 .
3. 制作Tomcat镜像
[root@ubuntu2004:/docker/tomcat]# ls
apache-tomcat-8.5.61.tar.gz Dockerfile
[root@ubuntu2004:/docker/tomcat]# cat Dockerfile
FROM centos7.9-jdk:8u271
LABEL maintainer=wuvikr message=Tomcat8.5.61-JDK8u271-Centos7.9
RUN mkdir /apps
ADD apache-tomcat-8.5.61.tar.gz /apps/
RUN ln -s /apps/apache-tomcat-8.5.61 /apps/tomcat
ENV TZ="Asia/Shanghai" LANG="en_US.UTF-8" TERM="xterm" TOMCAT_MAJOR_VERSION="8"
TOMCAT_MINOR_VERSION="8.5.61" CATALINA_HOME="/apps/tomcat"
APP_DIR="${CATALINA_HOME}/webapps" PATH="/apps/tomcat/bin:${PATH}"
[root@ubuntu2004:/docker/tomcat]# docker build -t centos7.9-tomcat:8.5.61 .
4. 制作web业务镜像
[root@ubuntu2004:/docker/web1]# ls
app.tar.gz Dockerfile run.sh server.xml
[root@ubuntu2004:/docker/web1]# cat run.sh
#!/bin/bash
su - www -c "/apps/tomcat/bin/catalina.sh run"
[root@ubuntu2004:/docker/web1]# cat Dockerfile
FROM centos7.9-tomcat:8.5.61
LABEL maintainer=wuvikr message=WEB1-Tomcat8.5.61-JDK8u271-Centos7.9
COPY server.xml /apps/tomcat/conf/server.xml
ADD app.tar.gz /data/tomcat/webapps/ROOT/
COPY run.sh /apps/tomcat/bin/
RUN echo "nameserver 114.114.114.114" >> /etc/resolv.conf
&& chown -R www.www /apps/ /data/
EXPOSE 8080 8009
CMD ["/apps/tomcat/bin/run.sh"]
[root@ubuntu2004:/docker/web1]# docker build -t centos7.9-tomcat8.5.61-web1:app .