博主语录:一文精讲一个知识点,多了你记不住,一句废话都没有
经典语录:一厢情愿,就得愿赌服輸
Dockerfile 由一行行命令语句组成,并且支持以 #开头的注释行。
一般而言,Dockerfile 可以分为四部分
FROM 指定基础镜像,最好挑一些 apline,slim 之类的基础小镜像
scratch 镜像是一个空镜像,常用于多阶段构建
如何确定我需要什么要的基础镜像?
标注镜像的一些说明信息。
LABEL multi.label1="value1" multi.label2="value2" other="value3"LABEL multi.label1="value1" \multi.label2="value2" \ other="value3"
RUN
( shell 形式, /bin/sh -c 的方式运行,避免破坏 shell 字符串) RUN ["executable", "param1", "param2"] ( exec 形式)
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
# 一个示例
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=
: ] ... COPY [--chown=
: ] [" ",... " "]
COPY hom* /mydir/ #当前上下文,以 home 开始的所有资源
COPY hom?.txt /mydir/ # ?匹配单个字符
COPY test.txt relativeDir/ # 目标路径如果设置为相对路径,则相对与 WORKDIR 开始
# 把 “test.txt” 添加到
/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
[: ]
USER 指令设置运行映像时要使用的用户名(或 UID)以及可选的用户组(或 GID),以及 Dockerfile 中 USER 后面所有 RUN,CMD 和 ENTRYPOINT 指令。
EXPOSE
[ / ...] 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" ]
aliyun
Nexus Snapshot Repository
https://maven.aliyun.com/repository/public
default
true
true
aliyun
Nexus Snapshot Repository
https://maven.aliyun.com/repository/public
default
true
true ######小细节
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 /appCOPY pom.xml .COPY src .RUN mvn clean package -Dmaven.test.skip=true# /app 下面有 targetRUN pwd && ls -lRUN cp /app/target/*.jar /app.jarRUN ls -l### 以上第一阶段结束,我们得到了一个 app.jar## 只要一个JRE# FROM openjdk:8-jre-alpineFROM openjdk:8u282-slimRUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo'Asia/Shanghai' >/etc/timezoneLABEL 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-alpineLABEL maintainer="lanson"COPY target/*.jar /app.jarRUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo'Asia/Shanghai' >/etc/timezone && touch /app.jarENV 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 | 留言与评论(共有 0 条评论) “” |