Dockerfile编写

可以用vs code编写

Dockerfile

Dockerfile是用来构建Docker镜像的文本文件,是由一条条构建镜像所需的指令和参数构成的脚本。

构建步骤:

  1. 编写Dockerfile文件
  2. docker build命令构建镜像
  3. docker run依据镜像运行容器实例

构建过程

Dockerfile编写:

  • 每条保留字指令都必须为大写字母,且后面要跟随至少一个参数
  • 指令按照从上到下顺序执行
  • #表示注释
  • 每条指令都会创建一个新的镜像层并对镜像进行提交

Docker引擎执行Docker的大致流程:

  1. docker从基础镜像运行一个容器
  2. 执行一条指令并对容器做出修改
  3. 执行类似docker commit的操作提交一个新的镜像层
  4. docker再基于刚提交的镜像运行一个新容器
  5. 执行Dockerfile中的下一条指令,直到所有指令都执行完成

指令

说明

FROM

指定基础镜像

MAINTAINER

指定维护者信息,已经过时,可以使用LABEL maintainer=xxx 来替代

RUN

运行命令 v

CMD

指定启动容器时默认的命令 v

ENTRYPOINT

指定镜像的默认入口.运行命令 v

EXPOSE

声明镜像内服务监听的端口 v

ENV

指定环境变量,可以在docker run的时候使用-e改变 v;会被固化到image的

config

ADD

复制指定的src路径下的内容到容器中的dest路径下,src可以为url会自动下载,

可以为tar文件,会自动解压

COPY

复制本地主机的src路径下的内容到镜像中的dest路径下,但不会自动解压等

LABEL

指定生成镜像的元数据标签信息

VOLUME

创建数据卷挂载点

USER

指定运行容器时的用户名或UID

WORKDIR

配置工作目录,为后续的RUN、CMD、ENTRYPOINT指令配置工作目录

ARG

指定镜像内使用的参数(如版本号信息等),可以在build的时候,使用--build

args改变 v

OBBUILD

配置当创建的镜像作为其他镜像的基础镜像是,所指定的创建操作指令

STOPSIGNAL

容器退出的信号值

HEALTHCHECK

健康检查

SHELL

指定使用shell时的默认shell类型

Dockerfile保留字

FROM

基础镜像,当前新镜像是基于哪个镜像的,指定一个已经存在的镜像作为模板。Dockerfile第一条必须是FROM

# FROM 镜像名
FROM hub.c.163.com/library/tomcat

LABEL

镜像维护者的姓名和邮箱地址

# 非必须
LABEL ZhangSan zs@163.com

RUN

容器构建时需要运行的命令。RUN是在docker build时运行

RUN <command> ( shell 形式, /bin/sh -c 的方式运行,避免破坏shell字符串)

RUN ["executable", "param1", "param2"] ( exec 形式)

RUN指令没有上下文的关系

RUN /bin/bash -c 'source $HOME/.bashrc; \
echo $HOME'
#上面等于下面这种写法
RUN /bin/bash -c 'source $HOME/.bashrc; echo $HOME'
RUN ["/bin/bash", "-c", "echo hello"]
# 测试案例
FROM alpine
LABEL maintainer=leifengyang xx=aa
ENV msg='hello atguigu itdachang'
RUN echo $msg
RUN ["echo","$msg"]
RUN /bin/sh -c 'echo $msg'
RUN ["/bin/sh","-c","echo $msg"]
CMD sleep 10000
#总结; 由于[]不是shell形式,所以不能输出变量信息,而是输出$msg。其他任何/bin/sh -c 的形式都
可以输出变量信息

总结:什么是shell和exec形式

1. shell 是 /bin/sh -c <command>的方式,
2. exec ["/bin/sh","-c",command] 的方式== shell方式
也就是exec 默认方式不会进行变量替换

ARG和ENV

ARG

ARG指令定义了一个变量,用户可以在构建时使用--build-arg = 传递,docker build命令会将其传递

给构建器。

构建时--build-arg 指定参数会覆盖Dockerfile 中指定的同名参数

如果用户指定了 未在Dockerfile中定义的构建参数 ,则构建会输出 警告 。

ARG只在构建期有效,运行期无效,且一次只能指定一个参数

ARG version=3.13.4
FROM alpine:$version

ENV

用来在构建镜像过程中设置环境变量。(构建期和运行期都生效)

  • 在构建阶段中所有后续指令的环境中使用,并且在许多情况下也可以内联替换。
  • 引号和反斜杠可用于在值中包含空格。
  • ENV 可以使用key value的写法,但是这种不建议使用了,后续版本可能会删除
# 格式 ENV 环境变量名 环境变量值
# 或者 ENV 环境变量名=值
ENV MY_PATH /usr/mytest
ENV MY_MSG hello
ENV MY_NAME="John Doe"
ENV MY_DOG=Rex\ The\ Dog
ENV MY_CAT=fluffy
#多行写法如下
ENV MY_NAME="John Doe" MY_DOG=Rex\ The\ Dog \
MY_CAT=fluffy
# 使用环境变量
WORKDIR $MY_PATH
  • docker run --env 可以修改这些值
  • 容器运行时ENV值可以生效
  • ENV在image阶段就会被解析并持久化(docker inspect image查看),测试如下
FROM alpine
ARG arg1=22222
ENV arg2=1111111
ENV runcmd=$arg1
RUN echo $arg1 $arg2 $runcmd
CMD echo $arg1 $arg2 $runcmd 
#构建完镜像如果docker run -e 修改arg1的值并不会改变runcmd的值,runcmd仍然等于原来arg1的值
#这里涉及到env持久化的问题

ADD和COPY

ADD

将宿主机目录下(或远程文件)的文件拷贝进镜像,且会自动处理URL和解压tar压缩包。

ADD URL   /dest #将文件下载到容器内部并以dest命名
ADD URL   /dest/ #将文件下载到容器内的/dest目录
ADD src   /dest/ #将本地文件传到容器/dest目录下,压缩文件会自动解压
  • src 路径必须在构建的上下文中; 不能使用 ../something /something 这种方式,因为docker 构建的第一步是将上下文目录(和子目录)发送到docker守护程序。
  • 如果 src 是URL,并且 dest 不以斜杠结尾,则从URL下载文件并将其复制到 dest 。
  • 如果 dest 以斜杠结尾,将自动推断出url的名字(保留最后一部分),保存到 dest
  • 如果 src 是目录,则将复制目录的整个内容,包括文件系统元数据。

COPY

复制文件夹

类似ADD,拷贝文件和目录到镜像中。

将从构建上下文目录中<源路径>的文件目录复制到新的一层镜像内的<目标路径>位置。

COPY src dest
COPY ["src", "dest"]
COPY [--chown=<user>:<group>] <src>... <dest>
COPY [--chown=<user>:<group>] ["<src>",... "<dest>"]
# <src源路径>:源文件或者源目录,src为上下文路径
# <dest目标路径>:容器内的指定路径,该路径不用事先建好。如果不存在会自动创建
COPY hom* /mydir/ #当前上下文,以home开始的所有资源
COPY hom?.txt /mydir/ # ?匹配单个字符
COPY test.txt relativeDir/ # 目标路径如果设置为相对路径,则相对与 WORKDIR 开始
# 把 “test.txt” 添加到 <WORKDIR>/relativeDir/
COPY test.txt /absoluteDir/ #也可以使用绝对路径,复制到容器指定位置
#所有复制的新文件都是uid(0)/gid(0)的用户,可以使用--chown改变
COPY --chown=55:mygroup files* /somedir/
COPY --chown=bin files* /somedir/
COPY --chown=1 files* /somedir/
COPY --chown=10:11 files* /somedir/

WORKDIR

指定在创建容器后, 终端默认登录进来的工作目录。

WORKDIR指令为Dockerfile中跟随它的所有 RUN,CMD,ENTRYPOINT,COPY,ADD 指令设置工作目 录。 如果WORKDIR不存在,即使以后的Dockerfile指令中未使用它也将被创建。

WORKDIR指令可在Dockerfile中多次使用。 如果提供了相对路径,则它将相对于上一个WORKDIR指

令的路径。 例如:

WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd
#结果 /a/b/c

也可以用到环境变量

ENV DIRPATH=/path
WORKDIR $DIRPATH/$DIRNAME
RUN pwd
#结果 /path/$DIRNAME

USER

指定该镜像以及构建镜像时的命令以什么样的用户去执行,如果不指定,默认是root。(一般不修改该配置),可搭配COPY使用。

# USER <user>[:<group>]
USER patrick
USER 1000:1000

VOLUME

作用:把容器的某些文件夹映射到主机外部

写法:

# VOLUME 挂载点
#无法指定宿主机的目录,会挂载到宿主机/var/lib/docker/volumes下随机生成的目录下
# 挂载点可以是一个路径,也可以是数组(数组中的每一项必须用双引号)
VOLUME ["/var/log/"] #可以是JSON数组
VOLUME /var/log #可以直接写
VOLUME /var/log /var/db #可以空格分割多个

注意:

用 VOLUME 声明了卷,那么以后对于卷内容的修改会被丢弃,即在dockerfile构建的时候无法再修改使用volume挂载出去的目录,所以, 一定在volume声明之前修改内容 ;另外docker commit提交新镜像的的时候也不会继承之前镜像的卷

EXPOSE

通知Docker容器在运行时在指定的网络端口上进行侦听。 可以指定端口是侦听TCP还 是UDP,如果未指定协议,则默认值为TCP。

EXPOSE指令实际上不会发布端口。 它充当构建映像的人员和运行容器的人员之间的一种文档,即

有关打算发布哪些端口的信息。 要在运行容器时实际发布端口,请在docker run上使用-p标志发布

并映射一个或多个端口,或使用-P标志发布所有公开的端口并将其映射到高阶端口。

EXPOSE <port> [<port>/<protocol>...]
EXPOSE [80,443]
EXPOSE 80/tcp
EXPOSE 80/udp

CMD和ENTRYPOINT

指定容器启动后要干的事情。

CMD 的三种写法:

  • CMD ["executable","param1","param2"] ( exec 方式, 首选方式)
  • CMD ["param1","param2"] (为ENTRYPOINT提供默认参数)
  • CMD command param1 param2 ( shell 形式)

ENTRYPOINT 的两种写法:

  • ENTRYPOINT ["executable", "param1", "param2"] ( exec 方式, 首选方式)
  • ENTRYPOINT command param1 param2 (shell 形式)

# 一个示例
FROM alpine
LABEL maintainer=liufengzhi
CMD ["1111"]
CMD ["2222"]
ENTRYPOINT ["echo"]
#构建出如上镜像后测试
docker run xxxx:效果 echo 2222

Dockerfile中如果出现多个CMD指令,只有最后一个生效。CMD会被docker run之后的参数替换。

只能有一个CMD

Dockerfile中只能有一条CMD指令。 如果您列出多个CMD,则只有最后一个CMD才会生效。

CMD的主要目的是为执行中的容器提供默认值。 这些默认值可以包含可执行文件,也可以省略可

执行文件,在这种情况下,您还必须指定ENTRYPOINT指令。

CMD为ENTRYPOINT提供默认参数

如果使用CMD为ENTRYPOINT指令提供默认参数,则CMD和ENTRYPOINT指令均应使用JSON数组格

式指定。

ENTRYPOINT

用来指定一个容器启动时要运行的命令。

类似于CMD命令,但是ENTRYPOINT不会被docker run后面的命令覆盖,这些命令参数会被当做参数送给ENTRYPOINT指令指定的程序。

ENTRYPOINT可以和CMD一起用,一般是可变参数才会使用CMD,这里的CMD等于是在给ENTRYPOINT传参。

当指定了ENTRYPOINT后,CMD的含义就发生了变化,不再是直接运行期命令,而是将CMD的内容作为参数传递给ENTRYPOINT指令,它们两个组合会变成 <ENTRYPOINT> "<CMD>"

例如:

FROM nginx

CMD ["/etc/nginx/nginx.conf"] # 变参
ENTRYPOINT ["nginx", "-c"]  # 定参

对于此Dockerfile,构建成镜像 nginx:test后,如果执行;

  • docker run nginx test,则容器启动后,会执行 nginx -c /etc/nginx/nginx.conf
  • docker run nginx:test /app/nginx/new.conf,则容器启动后,会执行 nginx -c /app/nginx/new.conf

构建镜像

实例:centos镜像里面集成vim,ifconfig,java,并且容器登入目录为/usr/local下

#创建目录
mkdir  /myfile
cd  /myfile  #将java压缩包传到/myfile下
vim  Dockfile
#内容如下
FROM centos:7.6.1810
MAINTAINER lfz

ENV MYPATH /usr/local
WORKDIR $MYPATH

#安装vim
RUN yum -y install vim
#安装ifconfig命令
RUN yum -y install net-tools
#安装java8及lib库
RUN yum -y install glibc.i686
RUN mkdir -p /usr/local/java
ADD  jdk-8u171-linux-x64.tar.gz  /usr/local/java/
#配置java环境变量
ENV JAVA_HOME /usr/local/java/jdk1.8.0_171
ENV JRE_HOME $JAVA_HOME/jre
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JRE_HOME/lib:$CLASSPATH
ENV PATH $JAVA_HOME/bin:$PATH

EXPOSE 80

CMD echo $MYPATH
CMD echo "success...........ok"
CMD /bin/bash

#之后构建镜像
docker  build -t centosjava8:1.5  . #.表示当前目录下构建
#启动容器查看是否符合要求
docker run -it  centosjava8:1.5 /bin/bash

多阶段构建

multi-stage builds

https://docs.docker.com/develop/develop-images/multistage-build/

解决:如何让一个镜像变得更小; 多阶段构建的典型示例

生产示例

#以下所有前提 保证Dockerfile和项目在同一个文件夹
# 第一阶段:环境构建; 用这个也可以
FROM maven:3.5.0-jdk-8-alpine AS builder
WORKDIR /app
ADD ./ /app
RUN mvn clean package -Dmaven.test.skip=true#第一阶段将jar包构建出来
# 第二阶段,最小运行时环境,只需要jre;第二阶段并不会有第一阶段哪些没用的层
#基础镜像没有 jmap; jdk springboot-actutor(jdk)
FROM openjdk:8-jre-alpine
LABEL maintainer="534096094@qq.com"
# 从上一个阶段复制内容
COPY --from=builder /app/target/*.jar /app.jar
# 修改时区
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo
'Asia/Shanghai' >/etc/timezone && touch /app.jar
ENV JAVA_OPTS=""
ENV PARAMS=""
# 运行jar包
ENTRYPOINT [ "sh", "-c", "java -Djava.security.egd=file:/dev/./urandom
$JAVA_OPTS -jar /app.jar $PARAMS" ]
######这样最后只构建了我们需要的第二个镜像####

实验

FROM golang:1.7.3 AS builder
WORKDIR /go/src/github.com/alexellis/href-counter/
RUN go get -d -v golang.org/x/net/html  
COPY app.go    .
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .
 
FROM alpine:latest  
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /go/src/github.com/alexellis/href-counter/app .###重要命令
CMD ["./app"]

Images瘦身实践

  • 选择最小的基础镜像
  • 合并RUN环节的所有指令,少生成一些层
  • RUN期间可能安装其他程序会生成临时缓存,要自行删除。如:
#生产环境
RUN apt-get update && apt-get install -y \
bzr \
cvs \
git \
mercurial \
subversion \
&& rm -rf /var/lib/apt/lists/

使用 .dockerignore 文件(在此文件编写需要忽略的目录和文件,构建的时候会忽略),排除上下文中无需参与构建的资源

使用多阶段构建

合理使用构建缓存加速构建。[--no-cache]

学习更多Dockerfile的写法:https://github.com/docker-library/

虚悬镜像

虚悬镜像:仓库名、标签名都是 <none>的镜像,称为 dangling images(虚悬镜像)。

在构建或者删除镜像时可能由于一些错误导致出现虚悬镜像。

例如:

# 构建时候没有镜像名、tag
docker build .

列出docker中的虚悬镜像:

docker image ls -f dangling=true

虚悬镜像一般是因为一些错误而出现的,没有存在价值,可以删除:

# 删除所有的虚悬镜像
docker image prune
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值