博主语录:一文精讲一个知识点,多了你记不住,一句废话都没有
经典语录:一厢情愿,就得愿赌服輸
Dockerfile由一行行命令语句组成,并且支持以#开头的注释行。
一般而言,Dockerfile可以分为四部分
指令 | 说明 |
---|---|
FROM | 指定基础镜像 |
MAINTAINER | 指定维护者信息,已经过时,可以使用LABELmaintainer-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时的默认shel类型 |
FROM 指定基础镜像,最好挑一些apline,slim之类的基础小镜像
scratch镜像是一个空镜像,常用于多阶段构建
如何确定我需要什么要的基础镜像?
标注镜像的一些说明信息。
LABEL multi.label1="value1" multi.label2="value2" other="value3"
LABEL multi.label1="value1" \
multi.label2="value2" \
other="value3"
RUN <command> ( shell 形式, /bin/sh -c 的方式运行,避免破坏shell字符串) RUN "executable", "param1", "param2" 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形式
CMD 的三种写法:
ENTRYPOINT 的两种写法:
一个示例 FROM alpine LABEL maintainer=leifengyang CMD "1111" CMD "2222" ENTRYPOINT "echo" #构建出如上镜像后测试 docker run xxxx:效果 echo 1111
无ENTRYPOINT | ENTRYPOINTexec_entryp1_entry | ENTRYPOINT"exec_entry"pl_entry" | |
---|---|---|---|
无CMD | 错误不允许的写法;容器没有启动命令 | /bin/sh-cexec_entryp1_entry | exec_entry pl_entry |
CMDexec_cmd","pl_cmd" | exec_cmd p1_cmd | /bin/sh-cexec_entryp1l_entry | exec_entry p1_entryexec_cmd p1_cmd |
CMD"p1_cmd","p2_cmd" | p1_cmd p2_cmd | /bin/sh-cexec_entrypl_entry | exec_entryp1_entry p1_cmdp2_cmd |
CMDexec_cmdp1_cmd | /bin/sh-c exec_cmdp1_cmd | /bin/sh-cexec_entrypl_entry | exec_entry p1_entry/bin/sh-c exec_cmdp1_cmd |
这条竖线,总是以ENTRYPOINT的为准 | 这条竖线,ENTRYPOINT和CMD共同作用 |
一个示例 FROM alpine LABEL maintainer=leifengyang CMD "1111" ENTRYPOINT "echo" #构建出如上镜像后测试 docker run xxxx:什么都不传则 echo 1111 docker run xxx arg1:传入arg1 则echo arg1
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
FROM alpine ENV arg=1111111 ENV runcmd=$arg RUN echo $runcmd CMD echo $runcmd #ENV的固化问题: 改变arg,会不会改变 echo的值,会改变哪些值,如何修改这些值?
FROM alpine ARG arg1=22222 ENV arg2=1111111 ENV runcmd=$arg1 RUN echo $arg1 $arg2 $runcmd CMD echo $arg1 $arg2 $runcmd
COPY的两种写法
COPY --chown=<user>:<group> <src>... <dest> COPY --chown=<user>:<group>
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/
同COPY用法,不过 ADD拥有自动下载远程文件和解压的功能。
注意:
WORKDIR /a WORKDIR b WORKDIR c RUN pwd #结果 /a/b/c
ENV DIRPATH=/path WORKDIR $DIRPATH/$DIRNAME RUN pwd #结果 /path/$DIRNAME
作用:把容器的某些文件夹映射到主机外部
写法:
VOLUME "/var/log/" #可以是JSON数组 VOLUME /var/log #可以直接写 VOLUME /var/log /var/db #可以空格分割多个
注意:
用 VOLUME 声明了卷,那么以后对于卷内容的修改会被丢弃,所以, 一定在volume声明之前修改内容 ;
写法:
USER <user>:<group> USER <UID>:<GID>
USER指令设置运行映像时要使用的用户名(或UID)以及可选的用户组(或GID),以及Dockerfile中USER后面所有RUN,CMD和ENTRYPOINT指令。
EXPOSE <port> <port>/<protocol>... EXPOSE 80,443 EXPOSE 80/tcp EXPOSE 80/udp
多阶段构建
https://docs.docker.com/develop/develop-images/multistage-build/
解决:如何让一个镜像变得更小; 多阶段构建的典型示例
我们如何打包一个Java镜像 FROM maven WORKDIR /app COPY . . RUN mvn clean package COPY /app/target/*.jar /app/app.jar ENTRYPOINT java -jar app.jar 这样的镜像有多大?我们最小做到多大?
以下所有前提 保证Dockerfile和项目在同一个文件夹第一阶段:环境构建; 用这个也可以 FROM maven:3.5.0-jdk-8-alpine AS builder WORKDIR /app ADD ./ /app RUN mvn clean package -Dmaven.test.skip=true 第二阶段,最小运行时环境,只需要jre;第二阶段并不会有第一阶段哪些没用的层基础镜像没有 jmap; jdk springboot-actutor(jdk) FROM openjdk:8-jre-alpine LABEL maintainer="lanson" 从上一个阶段复制内容 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" <!--为了加速下载需要在pom文件中复制如下 --> <repositories> <repository> <id>aliyun</id> <name>Nexus Snapshot Repository</name> <url>https://maven.aliyun.com/repository/public</url> <layout>default</layout> <releases> <enabled>true</enabled> </releases> <!--snapshots默认是关闭的,需要开启 --> <snapshots> <enabled>true</enabled> </snapshots> </repository> </repositories> <pluginRepositories> <pluginRepository> <id>aliyun</id> <name>Nexus Snapshot Repository</name> <url>https://maven.aliyun.com/repository/public</url> <layout>default</layout> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>true</enabled> </snapshots> </pluginRepository> </pluginRepositories> ######小细节 RUN /bin/cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai' >/etc/timezone 或者 RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai' >/etc/timezone 可以让镜像时间同步。 ## 容器同步系统时间 CST(China Shanghai Timezone) -v /etc/localtime:/etc/localtime:ro #已经不同步的如何同步? docker cp /etc/localtime 容器id:/etc/
docker build --build-arg url="git address" -t demo:test . :自动拉代码并构建镜像
FROM maven:3.6.1-jdk-8-alpine AS buildapp #第二阶段,把克隆到的项目源码拿过来 COPY --from=gitclone * /app/ WORKDIR /app COPY pom.xml . COPY src . RUN mvn clean package -Dmaven.test.skip=true /app 下面有 target RUN pwd && ls -l RUN cp /app/target/*.jar /app.jar RUN ls -l 以上第一阶段结束,我们得到了一个 app.jar只要一个JREFROM openjdk:8-jre-alpine FROM openjdk:8u282-slim RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai' >/etc/timezone LABEL maintainer="lanson" 把上一个阶段的东西复制过来 COPY --from=buildapp /app.jar /app.jar docker run -e JAVA_OPTS="-Xmx512m -Xms33 -" -e PARAMS="--spring.profiles=dev --server.port=8080" -jar /app/app.jar启动java的命令 ENV JAVA_OPTS="" ENV PARAMS="" ENTRYPOINT "sh", "-c", "java -Djava.security.egd=file:/dev/./urandom $JAVA_OPTS -jar /app.jar $PARAMS"
自己 写一个多阶段构建
开发期间,逐层验证正确的 RUN xxx RUN xxx RUN aaa \ aaa \ vvv \ 生产环境 RUN apt-get update && apt-get install -y \ bzr \ cvs \ git \ mercurial \ subversion \ && rm -rf /var/lib/apt/lists/*
学习更多Dockerfile的写法:https://github.com/docker-library/
FROM openjdk:8-jre-alpine LABEL maintainer="lanson" COPY 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="" ENTRYPOINT "sh", "-c", "java -Djava.security.egd=file:/dev/./urandom $JAVA_OPTS -jar /app.jar $PARAMS" 运行命令 docker run -e JAVA_OPTS="-Xmx512m -Xms33 -" -e PARAMS="--spring.profiles=dev --server.port=8080" -jar /app/app.jar
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。