Docker for Java Developers

1.  基本概念

1.1.  主要组件

Docker有三个主要组件:

  • 镜像是Docker的构建组件,而且是定义应用程序操作系统的只读模板
  • 容器是Docker的运行组件,它是从镜像创建的。容器可以运行、启动、停止、移动和删除
  • 镜像在注册中心中存储、共享和管理,并且是Docker的分发组件。Docker Store 是一个公开可用的注册中心。 

小编这里有一份Java学习资料,直接加我的Java直播学习群:697699179免费领取,你敢来我就敢送。

为了上这三个组件协同工作,Docker守护进程(或者叫Docker容器)运行在一个主机上,并负责构建、运行和分发Docker容器。此外,客户端是一个Docker二进制文件,它接受来自用户的命令并与引擎来回通信。

Docker for Java Developers

1.2.  Docker Image

Docker镜像是一个可以从其中启动Docker容器的只读模板。每个镜像又一系列的层组成。 (PS:现在发现,把“Image”翻译成专业术语“镜像”的话这里就感觉跟别扭。原文是“Each image consists of a series of layers”,如果按“Image”本来的意思“图像”去理解就很好理解了,对PhotoShop有点儿了解的人都能理解这句话,“图像由一系列图层组成”,真是太形象了。)

Docker如此轻量级的原因之一就是这些层(图层)。当你修改镜像(例如,将应用程序更新到新版本)时,将构建一个新的层。因此,只添加或更新该层,而不是像使用虚拟机那样替换整个映像或完全重建。现在,您不需要发布整个新图像,只需要更新即可,从而使分发Docker镜像更快、更简单。 (PS:越发觉得此处用“图像”更好理解,加个新图层或者在原先的图层上做修改即可)

每个镜像都是从一个基本镜像开始的。你也可以使用自己的镜像作为新镜像的基础。如果你有一个基本的Apache镜像,那么你可以使用它作为所有web应用程序镜像的基础。

Docker for Java Developers

Docker使用一组称为指令的简单描述性步骤来构建镜像。每条指令在镜像中创建一个新层。

  1. 运行一条命令
  2. 添加一个文件或目录
  3. 创建一个环境变量
  4. 当启动一个容器时运行一个进程

这些指令被存储在一个叫“Dockerfile”的文件中。当你请求构建镜像时,Docker读取这个Dockerfile文件,然后执行这些指令,并返回最终的镜像。

(PS:关于镜像,记住下面两句话

  • Each image consists of a series of layers.
  • Each instruction creates a new layer in our image. 

1.3.  Docker Container

容器由操作系统、用户添加的文件和元数据组成。正如我们所看到的,每个容器都是由一个镜像构建的。镜像告诉Docker容器持有什么、启动容器时运行什么进程以及各种其他配置数据。镜像是只读的。当Docker从映像运行容器时,它会在镜像之上添加一个读写层,然后你的应用程序就可以在其中运行了。

1.4.  Docker Engine

Docker Host是在安装Docker的时候创建的。一旦Docker Host被创建了,那么你就可以管理镜像和容器了。例如,你可以下载镜像、启动或停止容器。

1.5.  Docker Client

Docker Client与Docker Host通信,进而你就可以操作镜像和容器了。

2.  构建一个镜像

2.1.  Dockerfile

Docker通过从 Dockerfile 文件中读取指令来构建镜像。 Dockerfile 是一个文本文档,它包含用户可以在命令行上调用的所有命令来组装一个镜像。 docker image build 命令会使用这个文件,并执行其中的所有命令。

build 命令还传递一个在创建映像期间使用的上下文。这个上下文可以是本地文件系统上的路径,也可以是Git存储库的URL。

关于Dockerfile中可以使用的命令,详见  https://docs.docker.com/engine/reference/builder/

下面是一些常用的命令:

Docker for Java Developers

2.2.  创建你的第一个镜像

首先,创建一个目录hellodocker,然后在此目录下创建一个名为Dockerfile的文本文件,编辑该文件,内容如下:

Docker for Java Developers

从以上两行命令我们可以看到,该镜像是以ubuntu作为基础基础, CMD 命令定义了需要运行的命令。它提供了一个不同的入口 /bin/echo ,并给出了一个参数“hello world”。

Docker for Java Developers

Docker for Java Developers

2.3.  用Java创建你的第一个镜像

补充: OpenJDK 是Java平台标准版的一个开源实现,是Docker官方提供的镜像

Docker for Java Developers

首先,让我们创建一个java工程,然后打个jar包,接着创建并编辑Dockerfile

Docker for Java Developers

使用docker image build构建镜像

Docker for Java Developers

使用docker container run启动容器

Docker for Java Developers

其实,跟我们平常那一套没多大区别,不过是把打好的jar包做成镜像而已

2.4.  使用Docker Maven Plugin构建镜像

利用 Docker Maven Plugin 插件我们可以使用Maven来管理Docker镜像和容器。下面是一些预定义的目标:

Docker for Java Developers

详见  https://github.com/fabric8io/docker-maven-plugin

Docker for Java Developers

补充:Maven中的生命周期、阶段、目标

  1. 生命周期有三套:clean、default、site
  2. 生命周期由多个阶段组成的,比如default生命周期的阶段包括:clean、validate、compile、
  3. 每个阶段由多个目标组成,也就是说目标才是定义具体行为的
  4. 插件是目标的具体实现

稍微留一下IDEA里面的Maven区域就不难理解了

Docker for Java Developers

言归正传,利用docker-maven-plugin来构建镜像的方式有很多,比如,可以配置插件或属性文件,还可以结合Dockerfile,都在这里:

https://github.com/fabric8io/docker-maven-plugin/tree/master/samples

Docker for Java Developers

此处,我们演示用属性文件的方式,首先,定义一段profile配置,比如这样:

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 3          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 4     <modelVersion>4.0.0</modelVersion>
 5     <parent>
 6         <groupId>org.springframework.boot</groupId>
 7         <artifactId>spring-boot-starter-parent</artifactId>
 8         <version>2.1.4.RELEASE</version>
 9         <relativePath/> <!-- lookup parent from repository -->
10     </parent>
11     <groupId>com.cjs.example</groupId>
12     <artifactId>hello-demo</artifactId>
13     <version>0.0.1-SNAPSHOT</version>
14     <name>hello-demo</name>
15     <description>Demo project for Spring Boot</description>
16 
17     <properties>
18         <java.version>1.8</java.version>
19     </properties>
20 
21     <dependencies>
22         <dependency>
23             <groupId>org.springframework.boot</groupId>
24             <artifactId>spring-boot-starter-web</artifactId>
25         </dependency>
26 
27         <dependency>
28             <groupId>org.springframework.boot</groupId>
29             <artifactId>spring-boot-starter-test</artifactId>
30             <scope>test</scope>
31         </dependency>
32     </dependencies>
33 
34     <build>
35         <plugins>
36             <plugin>
37                 <groupId>org.springframework.boot</groupId>
38                 <artifactId>spring-boot-maven-plugin</artifactId>
39             </plugin>
40         </plugins>
41     </build>
42 
43     <profiles>
44         <profile>
45             <id>docker</id>
46             <build>
47                 <plugins>
48                     <plugin>
49                         <groupId>io.fabric8</groupId>
50                         <artifactId>docker-maven-plugin</artifactId>
51                         <version>0.30.0</version>
52                         <configuration>
53                             <images>
54                                 <image>
55                                     <name>hellodemo</name>
56                                     <build>
57                                         <from>openjdk:latest</from>
58                                         <assembly>
59                                             <descriptorRef>artifact</descriptorRef>
60                                         </assembly>
61                                         <cmd>java -jar maven/${project.name}-${project.version}.jar</cmd>
62                                     </build>
63                                 </image>
64                             </images>
65                         </configuration>
66                         <executions>
67                             <execution>
68                                 <id>docker:build</id>
69                                 <phase>package</phase>
70                                 <goals>
71                                     <goal>build</goal>
72                                 </goals>
73                             </execution>
74                             <execution>
75                                 <id>docker:start</id>
76                                 <phase>install</phase>
77                                 <goals>
78                                     <goal>run</goal>
79                                     <goal>logs</goal>
80                                 </goals>
81                             </execution>
82                         </executions>
83                     </plugin>
84                 </plugins>
85             </build>
86         </profile>
87     </profiles>
88 </project> 

然后,在构建的时候指定使用docker这个profile即可

1 mvn clean package -Pdocker

Docker for Java Developers

Docker for Java Developers

2.5.  Dockerfile命令(番外篇)

CMD 与 ENTRYPOINT 的区别

容器默认的入口点是 /bin/sh ,这是默认的shell。

当你运行 docker container run -it ubuntu 的时候,启动的是默认shell。

Docker for Java Developers

ENTRYPOINT 允许你覆盖默认的入口点。例如:

Docker for Java Developers

这里默认的入口点被换成了/bin/cat

ADD 与 COPY 的区别

ADD有COPY所有的能力,而且还有一些额外的特性:

  1. 允许在镜像中自动提取tar文件
  2. 允许从远程URL下载文件 

3.  运行一个Docker容器

3.1.  交互

以交互模式运行WildFly容器,如下:

1 docker container run -it jboss/wildfly

默认情况下,Docker在前台运行。 -i 允许与STDIN交互, -t 将TTY附加到进程上。它们可以一起用作 -it

按Ctrl+C停止容器

3.2.  分离容器

1 docker container run -d jboss/wildfly

用-d选项代替-it,这样容器就以分离模式运行

(PS:-it前台运行,-d后台运行)

3.3.  用默认端口

如果你想要容器接受输入连接,则需要在调用docker run时提供特殊选项。 

1 $ docker container ls
2 CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
3 93712e8e5233        jboss/wildfly       "/opt/jboss/wildfly/…"   4 minutes ago       Up 4 minutes        8080/tcp            serene_margulis
4 02aa2ed22725        ubuntu              "/bin/bash"              2 hours ago         Up 2 hours                              frosty_bhabha 

重启容器

1 docker container stop `docker container ps | grep wildfly | awk '{print $1}'`
2 docker container run -d -P --name wildfly jboss/wildfly

-P选项将镜像中的任何公开端口映射到Docker主机上的随机端口。--name选项给这个容器起个名字。

1 $ docker container ls
2 CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                     NAMES
3 3f2babcc1df7        jboss/wildfly       "/opt/jboss/wildfly/…"   47 seconds ago      Up 47 seconds       0.0.0.0:32768->8080/tcp   wildfly

Docker for Java Developers

3.4.  用指定端口

1 docker container stop wildfly
2 docker container rm wildfly 

或者你还可以用 docker container rm -f wildfly 来停止并删除容器

1 docker container run -d -p 8080:8080 --name wildfly jboss/wildfly

格式是: -p hostPort:containerPort 

此选项将主机上的端口映射到容器中的端口。这样就使得我们可以通过主机上的特定的端口来访问容器。

现在我们访问http://localhost:8080/跟刚才http://localhost:32768/是一样的 

3.5.  停止容器

1 # 按id或name停止指定的容器
2 docker container stop <CONTAINER ID>
3 docker container stop <NAME>
4 
5 # 停止所有容器
6 docker container stop $(docker container ps -q)
7 
8 # 停止已经退出的容器
9 docker container ps -a -f "exited=-1"

3.6.  删除容器

1 # 按id或name删除指定的容器
2 docker container rm <CONTAINER ID>
3 docker container rm <NAME>
4 
5 # 用正则表达式删除匹配到的容器
6 docker container ps -a | grep wildfly | awk '{print $1}' | xargs docker container rm
7 
8 # 删除所有容器
9 docker container rm $(docker container ps -aq)

3.7.  查看端口映射

1 docker container port <CONTAINER ID> or <NAME>

小编这里有一份Java学习资料,直接加我的Java直播学习群:697699179免费领取,你敢来我就敢送。

上一篇:java – com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException:’字段列表’中的未知列’day0_.calendar_id’


下一篇:Java之类加载器