Dockerfile 实践及梳理
Dockerfile 是一个文本文件,我们可以通过组合一条条的指令 (Instruction),来构建满足我们需求的 Docker 镜像
文档
Best practices for writing Dockerfiles
简单上手
使用 Dockerfile 构建SpringBoot 工程的镜像
- 新建 SpringBoot 项目,默认的端口是 8080 ,新建 Controller 和 Mapping
@RestController
public class HelloController {
@GetMapping("hello")
public String hello() {
return "hello world!";
}
}
启动项目,访问 http://localhost:8080/hello 测试
- 打 jar 包
注意,需要在 pom 中添加 spring-boot-maven-plugin 插件,否则运行 jar 包时会提示:没有主清单属性
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
#打包
mvn package
target 目录下就可以找到 .jar 文件,我这里的文件名为:demo-0.0.1-SNAPSHOT.jar
在 Linux 新建 ~/springboot
文件夹,并将 jar 包上传到这个文件夹下
- 新建 Dockerfile
在这个文件下新建 Dockerfile 文件
# 基于 openjdk:8-jre 这个基础镜像进行构建
FROM openjdk:8-jre
# 这里的 demo-0.0.1- SNAPSHOT.jar 要对应上传的 jar 包名称
# 将 本地 jar包 复制到容器内
COPY demo-0.0.1-SNAPSHOT.jar app.jar
# 开放 8080 端口
EXPOSE 8080
# 运行命令、参数
ENTRYPOINT ["java","-jar"]
CMD ["app.jar"]
保存文件,退出编辑器
- 编译 Docker 镜像
# build 是构建 Docker 镜像的命令
# -t 指定镜像的 tag
# 名称:demo 版本:v1.0
# 最后的 . 表示 build context 目录为当前目录,目的是为了找到 所需的 jar 包
docker build -t demo:v1.0 .
- 启动容器
# 前台启动刚构建的 SpringBoot 容器
# -p 映射容器8080端口 到宿主机的 8080 上
docker run -p 8080:8080 demo:v1.0
- 测试
访问 Linux 的8080 端口,注意替换为自己的 Linux 的地址,并开放 8080 端口
http://192.168.43.161:8080/hello
build context
Dockerfile 默认会使用它自己所在的目录作为 context,通过 docker 执行构建命令后,Docker daemon 会拷贝 context 目录下的所有文件
,所以 context 目录不要放置项目无关的文件,或者可以使用 .dockerignore
定义忽略文件,也可以指定 context 路径
# build 命令通过 Dockerfile 构建镜像
# 指定 ~/dockerfile 为 build context
docker build ~/dockerfile
# 不需要添加文件到 context 可以使用 -
docker build -
可以通过 stdin 的方式,避免生产 Dockerfile 文件,直接 build 镜像
docker build -t myimage:latest -<<EOF
FROM busybox
RUN echo "hello world"
EOF
除了可以指定 context外,还可以通过-f 指定 Dockerfile 所在的路径
docker build -f dockerfiles/Dockerfile .
最佳实践
非常推荐官方的 Dockerfile最佳实践:Best practices for writing Dockerfiles
- 每个容器单一职责,有利于横向拓展和复用
- 旧版强调减少层数以提高性能,现在只有 RUN, COPY, ADD 这几个命令会创建层,其他命令只会创建中间层。并且只有使用到资源最终会被拷贝到最终镜像
- 多个参数按字母顺序排列,并使用空格和
\
进行分割,提高可读性 --no-cache
不使用缓存,默认 build 过程中如果检查到有可重用的镜像层则使用。从基础镜像开始,每一条命令逐一检查,如果命令不一样则缓存失效。使用ADD
和COPY
则会校验使用到的文件校验和
是否相同,除了这两个命令,其他则不会通过文件变化来决定是否匹配缓存,而是仅通过命令本身是否一致来判断是否匹配缓存,比如:RUN apt-get -y update
会改变容器内的文件,但是也只使用这个命令匹配缓存,而不会通过文件的变动。一旦缓存失效,后续都会产生新的镜像层
Dockerfile 指令 (instructions)
FROM
Dockerfile 的第一个命令一般都是 FROM,通过这个指定该镜像的 Base Image,推荐基础镜像:alpine,因为它完整且轻量,如果不需要 Base Image 可以用 FROM scratch
,代表该镜像基于一个空镜像进行构建
RUN
由于上面提到的缓存匹配原则,RUN apt-get update
命令可能会导致直接使用了原来缓存的镜像层,而没有执行该命令获取最新的软件列表,可以使用 RUN apt-get update && apt-get install -y
来使缓存失效
可以使用 \
分割,提高可读性:
RUN apt-get update && apt-get install -y \
curl
CMD
指定容器启动时运行的命令,通常默认采用的格式:CMD ["executable", "param1", "param2"…]
,如:
CMD ["perl", "-de0"]
这样使用 docker run -it
命令进入容器时,就会默认进入 shell 界面
EXPOSE
指定容器需要监听的端口
ENV
可以使用 ENV 更新 PATH 环境变量,例如
ENV PATH=/usr/local/nginx/bin:$PATH
注意!每一个 ENV
指令都会创建一个新的中间层 (intermediate layer),如果使用 ENV 设置了变量,在未来的层 unset 了变量,那么它在 unset 之前依然是可用的。为了防止这种情况,我们应该用 RUN 进行环境变量的 设置和取消
ENV ADMIN_USER="mark"
RUN echo $ADMIN_USER > ./mark
RUN unset ADMIN_USER
ADD or COPY
两个命令功能相似,优先使用COPY,它的作用只是将本地文件拷贝到容器内,而 ADD 则有其他特性,比如:自动将本地 tar 文件提取到镜像中、远程URL
如果多个步骤需要使用不同的文件,应该单独 COPY,而不是一次性 COPY,这样部分文件变化不会导致所有的缓存都失效
避免使用 ADD 通过 URL 获取包,可以使用 curl
或者 wget
,这样可以在提取后删除文件,避免镜像多一层,还可以通过管道,就不需要再手动删除中间文件
RUN mkdir -p /usr/src/things \
&& curl -SL https://example.com/big.tar.xz \
| tar -xJC /usr/src/things \
&& make -C /usr/src/things all
ENTRYPOINT
使用 ENTRYPOINT 设置主命令,还可以用 CMD 设置默认的可选参数
ENTRYPOINT ["s3cmd"]
CMD ["--help"]
运行编译镜像,指定名称为:s3cmd,运行容器
docker run s3cmd
默认会运行 s3cmd
并带上 --help
参数,即:显示该命令的帮助
运行下面命令:
docker run s3cmd ls s3://mybucket
ls s3://mybucket
会覆盖默认可选参数 --help
如果需要覆盖 ENTRYPOINT,需要使用 --entrypoint
参数
VOLUME
暴露镜像中可变和用户可修改的数据,比如:存储文件、配置文件,比如:
VOLUME /data
设置的目录会在容器运行时自动挂载为匿名卷,如果没有设置,就会写入容器存储层
USER
如果不需要使用 sudo
,可以通过 USER 切换到非 root 用户,例如:
RUN groupadd -r postgres && useradd --no-log-init -r -g postgres postgres
WORKDIR
WORKDIR 指令可以来指定工作目录,不存在会自动创建
Dockerfile 不同于 Shell,下面的命令其实是不同的层,第一条的 cd
不会影响第二条命令,最终运行结束会导致在 /app 下找不到 world.txt 文件
RUN cd /app
RUN echo "hello" > world.txt
应该使用:
WORKDIR /app
RUN echo "hello" > world.txt
参考资料
Dockerfile 实践及梳理的更多相关文章
- Docker Compose 实践及梳理
Docker Compose 可以实现 Docker 容器集群的编排,可以通过 docker-compose.yml 文件,定义我们的服务及其需要的依赖,轻松地运行在测试.生产等环境 文档 Produ ...
- [转]docker之Dockerfile实践
本文转自:https://www.cnblogs.com/jsonhc/p/7767669.html 上一篇介绍了Dockerfile中使用的指令,现在开始进行指令实践 先查看下本地的镜像,选一个作为 ...
- docker之Dockerfile实践
上一篇介绍了Dockerfile中使用的指令,现在开始进行指令实践 先查看下本地的镜像,选一个作为base image: [root@docker ~]# docker images REPOSITO ...
- 【转】docker之Dockerfile实践
转自:https://www.cnblogs.com/jsonhc/p/7767669.html 上一篇介绍了Dockerfile中使用的指令,现在开始进行指令实践 先查看下本地的镜像,选一个作为ba ...
- <创新思维与实践>总结梳理
2017年12月3-4号 培训了两天的创新思维与实践,有时间要补充总结一下. ---todo
- Dockerfile极简入门与实践
前文中,罗列了docker使用中用到的基本命令 此文,将会对怎样使用Dockerfile去创建一个镜像做简单的介绍 Dockerfile命令 要开始编写Dockerfile,首先要对相关的命令有个清晰 ...
- Docke--Dockerfile实践
Dockerfile 实践 nginx镜像构建 先查看下本地的镜像,选取官网的centos作为base image: [root@server ~]# docker images REPOSITORY ...
- docker:Dockerfile构建LNMP平台
docker:Dockerfile构建LNMP平台 1.dockerfile介绍 Dockerfile是Docker用来构建镜像的文本文件,包含自定义的指令和格式.可以通过docker buil ...
- Docker 入门指南——Dockerfile 指令
COPY 复制文件 格式: COPY [--chown=<user>:<group>] <源路径>... <目标路径> 源路径可以是多个,甚至可以使通配 ...
随机推荐
- node.js背后的引擎V8及优化技术
本文将挖掘V8引擎在其它方面的代码优化,如何写出高性能的代码,及V8的性能诊断工具.V8是chrome背后的javascript引擎,因此本文的相关优化经验也适用于基于chrome浏览器的javasc ...
- 一次搞懂JavaScript对象
索引 目录 索引 1. 对象与类 2.对象使用 2.1 语法 2.2 属性 3.对象特性 4.对象的创建 4.1 字面量 4.2 工厂函数 4.3 构造函数 4.4 class类 4.5 对象与单例模 ...
- 【Uva1025 A Spy in the Metro】动态规划
题目描述 某城市地铁是线性的,有n(2≤n≤50)个车站,从左到右编号1~n.有M1辆列车从第1站开始往右开,还有M2辆列车从第n站开始往左开.列车在相邻站台间所需的运行时间是固定的,因为所有列车的运 ...
- dva的effect那么难用,自己造一个轮子吧
背景 对于dva这个开发框架,国内从事react的前端工程师多半不会感到陌生,dva完善的开发体系和简单的api,让其被广泛运用到实际工作中.我所在的公司也是长期使用dva作为基础的开发框架,虽然好用 ...
- decimal和float的区别
场景 今天在开发的时候,在mongodb中有个字段保存的数据结构是decimal,然后需要对这个字段的值进行范围的查询.结果却怎么查询值范围都是空. 解决 如图中看到的,利用Navicat,可以明显的 ...
- js 数据存入数组
var tag = []; $('.deltag').each(function(){ if($(this).attr("checked")== 'checked'){ tag.p ...
- 硬核万字长文,深入理解 Java 字节码指令(建议收藏)
Java 字节码指令是 JVM 体系中非常难啃的一块硬骨头,我估计有些读者会有这样的疑惑,"Java 字节码难学吗?我能不能学会啊?" 讲良心话,不是我谦虚,一开始学 Java 字 ...
- Elasticsearch(9300、9200)未授权访问
下载地址https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-5.5.0.zip 检测 http://localhost ...
- JAVA虚拟机的组成>从零开始学java系列
目录 JAVA虚拟机的组成 什么是虚拟机? JAVA虚拟机的组成部分 堆区(堆内存) 方法区 虚拟机栈 本地方法栈 程序计数器 字符串常量池 JAVA虚拟机的组成 什么是虚拟机? 虚拟机是运行在隔离环 ...
- 使用 Assimp 库加载 3D 模型
前言 要想让自己的 3D 之旅多一点乐趣,肯定得想办法找一些有意思一点的 3D 模型.3D 模型有各种各样的格式,obj的,stl的,fbx的等等不一而足.特别是 obj 格式的 3D 模型,完全是纯 ...