Docker for Java Developers


1.  基本概念

1.1.  主要組件

Docker有三個主要組件:

  • 鏡像是Docker的構建組件,而且是定義應用程序操作系統的只讀模板
  • 容器是Docker的運行組件,它是從鏡像創建的。容器可以運行、啟動、停止、移動和刪除
  • 鏡像在注冊中心中存儲、共享和管理,並且是Docker的分發組件。Docker Store 是一個公開可用的注冊中心。https://hub.docker.com/

為了上這三個組件協同工作,Docker守護進程(或者叫Docker容器)運行在一個主機上,並負責構建、運行和分發Docker容器。此外,客戶端是一個Docker二進制文件,它接受來自用戶的命令並與引擎來回通信。

1.2.  Docker Image

Docker鏡像是一個可以從其中啟動Docker容器的只讀模板。每個鏡像又一系列的層組成。(PS:現在發現,把“Image”翻譯成專業術語“鏡像”的話這里就感覺跟別扭。原文是“Each image consists of a series of layers”,如果按“Image”本來的意思“圖像”去理解就很好理解了,對PhotoShop有點兒了解的人都能理解這句話,“圖像由一系列圖層組成”,真是太形象了。)

Docker如此輕量級的原因之一就是這些層(圖層)。當你修改鏡像(例如,將應用程序更新到新版本)時,將構建一個新的層。因此,只添加或更新該層,而不是像使用虛擬機那樣替換整個映像或完全重建。現在,您不需要發布整個新圖像,只需要更新即可,從而使分發Docker鏡像更快、更簡單。(PS:越發覺得此處用“圖像”更好理解,加個新圖層或者在原先的圖層上做修改即可)

每個鏡像都是從一個基本鏡像開始的。你也可以使用自己的鏡像作為新鏡像的基礎。如果你有一個基本的Apache鏡像,那么你可以使用它作為所有web應用程序鏡像的基礎。

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/

下面是一些常用的命令:

2.2.  創建你的第一個鏡像

首先,創建一個目錄hellodocker,然后在此目錄下創建一個名為Dockerfile的文本文件,編輯該文件,內容如下:

從以上兩行命令我們可以看到,該鏡像是以ubuntu作為基礎基礎,CMD命令定義了需要運行的命令。它提供了一個不同的入口/bin/echo,並給出了一個參數“hello world”。

2.3.  用Java創建你的第一個鏡像

補充:OpenJDK是Java平台標准版的一個開源實現,是Docker官方提供的鏡像

首先,讓我們創建一個java工程,然后打個jar包,接着創建並編輯Dockerfile

使用docker image build構建鏡像

使用docker container run啟動容器

其實,跟我們平常那一套沒多大區別,不過是把打好的jar包做成鏡像而已

2.4.  使用Docker Maven Plugin構建鏡像

利用Docker Maven Plugin插件我們可以使用Maven來管理Docker鏡像和容器。下面是一些預定義的目標:

詳見 https://github.com/fabric8io/docker-maven-plugin

補充:Maven中的生命周期、階段、目標

  1. 生命周期有三套:clean、default、site
  2. 生命周期由多個階段組成的,比如default生命周期的階段包括:clean、validate、compile、
  3. 每個階段由多個目標組成,也就是說目標才是定義具體行為的
  4. 插件是目標的具體實現

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

言歸正傳,利用docker-maven-plugin來構建鏡像的方式有很多,比如,可以配置插件或屬性文件,還可以結合Dockerfile,都在這里:

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

此處,我們演示用屬性文件的方式,首先,定義一段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

 

 

2.5.  Dockerfile命令(番外篇)

CMD 與 ENTRYPOINT 的區別

容器默認的入口點是 /bin/sh,這是默認的shell。

當你運行 docker container run -it ubuntu 的時候,啟動的是默認shell。

ENTRYPOINT 允許你覆蓋默認的入口點。例如:

 

這里默認的入口點被換成了/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

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>

4.  參考

https://github.com/docker/labs/tree/master/developer-tools/java/ 

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

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM