本文记录生成自己的 Docker 镜像的两个例子. 第一个是在一个 SpringBoot 工程基础上生成镜像, 第二个是在普通的基于 Tomcat 的 web 工程的基础上生成镜像.
Docker 常用命令
列出所有镜像(加上参数 - a 可以包括中间层镜像, 还有 - q 和 --format 等实用参数)
docker image ls
查看镜像, 容器, 数据卷所占用的空间
docker system df
删除镜像
docker image rm [选项] <镜像 1> [<镜像 2> ...]
启动镜像
docker run [OPTIONS] <镜像>
[OPTIONS]常用参数:
-d: 后台运行容器, 并返回容器 ID;
-i: 以交互模式运行容器, 通常与 -t 同时使用;
-t: 为容器重新分配一个伪输入终端, 通常与 -i 同时使用;
-p: 端口映射, 格式为: 主机 (宿主) 端口: 容器端口;
--name "xxx": 为容器指定一个名称;
以交互式终端方式进入容器
docker exec -it <容器名>
使用 Dockerfile 创建镜像, 这个后面必须跟参数, 且须有一个.
docker build
生成 SpringBoot 的 Web 工程的镜像
创建 SpringBoot 的工程
首先创建一个简单的 SpringBoot 工程, 工程很简单, 功能是访问 localhost:8080 从而跳转到指定页面. 工程中只有一个 TestController, 这个 TestController 的默认路径指向 index.html 页面, 这个 index.HTML 在 resources 目录下的 templates.home 中. static.home 可以忽略, 其中存的只是 index.HTML 的样式文件.
工程目录结构如下:
SpringBoot 工程目录结构
TestController 的内容, 没有任何逻辑, 只是跳转到 index.HTML 页面:
- package com.example.learndocker.controller;
- import org.springframework.stereotype.Controller;
- import org.springframework.Web.bind.annotation.RequestMapping;
- @Controller
- @RequestMapping("/")
- public class TestController {
- @RequestMapping(value = "")
- public String home() {
- return "home/index";
- }
- }
为了返回页面, 需要引用模板引擎, pom.xml 如下:
- <?xml version="1.0" encoding="UTF-8"?>
- <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <parent>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-parent</artifactId>
- <version>2.1.3.RELEASE</version>
- <relativePath/> <!-- lookup parent from repository -->
- </parent>
- <groupId>com.example</groupId>
- <artifactId>learn-docker</artifactId>
- <version>0.0.1-SNAPSHOT</version>
- <name>learn-docker</name>
- <description>sth about docker</description>
- <properties>
- <java.version>1.8</java.version>
- </properties>
- <dependencies>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-Web</artifactId>
- <version>2.1.3.RELEASE</version>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-test</artifactId>
- <scope>test</scope>
- </dependency>
- <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-thymeleaf -->
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-thymeleaf</artifactId>
- <version>2.1.3.RELEASE</version>
- </dependency>
- </dependencies>
- <build>
- <plugins>
- <plugin>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-maven-plugin</artifactId>
- </plugin>
- </plugins>
- </build>
- </project>
执行 LearnDockerApplication 的 main 方法, 在浏览器访问 localhost:8080, 可以看到如下页面:
SpringBoot 启动后访问 localhost:8080
生成 Docker 镜像
接下来生成 docker 镜像. 首先将 SpringBoot 打成 jar 包, 然后在任意位置创建 Dockerfile 文件, 我是在 learn-docker 的工程目录下创建的, 为了方便, 我直接在 IDEA 中编辑了.
添加了 Dockerfile 文件, 并且打包工程之后, 工程目录结构如下:
Dockerfile 所在目录
Dockerfile 所在目录
Dockerfile 内容如下:
- #docker 仓库的 JDK 镜像
- FROM java:8
- # 挂载点 (根据需要可以不要), 即容器中 / tmp(这个目录是 springboot 内嵌的 Tomcat 默认使用目录) 的改动会同步到主机的指定目录
- VOLUME /tmp
- # 将自己的 jar 包加入生成的镜像中(在 JDK 这一层的基础上加上我们的 jar 构建新的镜像)
- ADD target/learn-docker-0.0.1-SNAPSHOT.jar learn-docker.jar
- # 容器启动完执行
- ENTRYPOINT ["java","-jar","learn-docker.jar"]
分析: 运行 springboot 的 Web 工程, 需要操作系统 + JDK/JRE, 所以需要以操作系统镜像作为基础, 然后加入 JDK/JRE, 再加上自己的 jar, 生成自定义镜像.
但是因为 Docker 镜像是分层构建, 所以官方的 java:8 镜像中已经包含了操作系统的镜像这一层, 所以此处直接引用此基础镜像即可. 然后加入我们自己的 jar, 在基础镜像的基础上生成新的镜像. 并设置当启动容器时, 启动 springboot 的 jar 包即可.
当然, 如果不想使用现有的 Java 镜像, 也可以下载好 JDK/JRE, 并以现有的操作系统的镜像为基础(有很多优化过的体积很小的操作系统基础镜像, 比如 alpine), 加入 JDK/JRE, 同时加入我们自己的 jar, 配置好 Java 环境变量, 生成新的镜像, 这样会使得新镜像的层数少一层, 原则上是层数越少越好.
执行命令 docker build -t learndocker:v1 . 构建镜像, 注意命令后面有一个. 不能少, 构建过程:
镜像构建过程
构建完毕之后:
构建镜像完毕
此时 docker images 查看镜像, 可以看到刚构建完的自己命名的 learndocker:v1, 当然同时也下载了 java:8 的镜像(这里可以看出分层构建镜像的思想).kafka 镜像是本人之前下载的.
查看镜像. jpg
此时可以正常启动容器并将宿主的 8080 端口与镜像的 8080 端口映射, 执行命令 docker run -p 8080:8080 <镜像 id>, 此时我并没有让容器在后台启动, 所以当我退出终端时, 容器会停止.
启动容器
保持终端不关闭, 此时访问浏览器 localhost:8080, 可以看到与之前同样的页面, 整个定制镜像并启动的过程成功.
为了理解挂载点的意思, 在启动时使用 docker run -v /Users/shakeli/idea_workspace/learn-docker/test:/tmp -p 8080:8080 6b2bd203cc3f 来启动, 即使用 - v 参数加了宿主目录与容器目录的映射关系, 那么会在 / Users/shakeli/idea_workspace/learn-docker/test 的目录下, 同步容器中 / tmp 目录中的内容(如果 test 目录不存在会自动生成):
1552494286526.jpg
生成正常 Web 工程的 Docker 镜像
经过上面的分析, 我们可以分析如果只是正常的 Web 工程, 我们的 Dockerfile 最少需要哪些指令. 由于 springboot 集成了 Tomcat, 而如果不用 springboot, 那么我们需要加上 Tomcat, 理论上来说如果从 0 构建, 那么需要: 操作系统 + JDK/JRE+Tomcat.
由于 JDK/JRE 需要操作系统, 而 Tomcat 又需要 JDK/JRE, 那么如果我们以现有的官方镜像为基础, 实际上只需要 Tomcat 的作为基础镜像即可, 当然, 如果不使用现有的 Tomcat 镜像, 而是以操作系统镜像为基础, 加入 JDK/JRE, 加入 Tomcat, 会比使用现有 Tomcat 作为基础镜像少一层.
未完待续......
附 Dockerfile 常用指令
附 Dockerfile 的常用指令
FROM <image>:<tag> 指定基础镜像, 必须在 Dockerfile 第一行
MAINTAINER <name > 指定维护者信息
RUN <command > 在镜像中要执行的命令
WORKDIR: 指定当前工作目录, 相当于 cd
EXPOSE <port> [<port>...]指定容器要打开的端口
ENV <key> <value > 或者 ENV <key>=<value> ... 指定一个 / 多个环境变量, 会被后续 RUN 指令使用, 并在容器运行时保持
ADD <src> <dest > 把文件复制到镜像中, src 可以是链接
COPY <src>... <dest>COPY 的 < src > 只能是本地文件, 其他用法与 ADD 一致
CMD 或 ENTRYPOINT 容器启动时执行的命令, 两者有些许区别, 可以组合使用
ARG <name>[=<default value>] 设置变量
IDEADocker 插件
未完待续......
参考
Docker -- 从入门到实践 https://yeasy.gitbooks.io/docker_practice/content/
Docker 命令大全
Dockerfile 命令详解(超全版本)
来源: http://www.jianshu.com/p/9f17dcc6c62e