執行簡單的Java程式
先在當前目錄建立App.java檔案
public class App{
public static void main(String[] args){
String os = System.getProperty("os.name");
String osArch = System.getProperty("os.arch");
String osVersion = System.getProperty("os.version");
System.out.println(os);
System.out.println(osArch);
System.out.println(osVersion);
}
}
然後建立Dockerfile
## 設定基礎映象
FROM openjdk:8
## 設定進入容器時的工作目錄
WORKDIR /root/app
## 將本地目錄複製進容器目錄中
COPY App.java /root/app
## 映象製作時執行的命令
RUN javac App.java
## 容器啟動時執行的命令
ENTRYPOINT java App
準備工作做好之後在當前目錄輸入命令
docker build .
.
是指明Dockerfile檔案在哪個路徑之下,因為我們是在當前路徑下建立的,所以只需要填寫.
就好。
build完成之後執行命令:
docker images
## 你的輸出可能會像這樣
REPOSITORY TAG IMAGE ID CREATED SIZE
<none> <none> 2045f43c5e88 6 hours ago 526MB
REPOSITORY
和TAG
都為<none>
,這是因為剛剛在編寫Dockerfile
時沒有指定它們。
之後的段落裡會解決這個問題,對於這個簡單的專案,我們只需要IMAGE ID
就夠了。
現在根據映象啟動容器,執行命令:
## 偷懶的話可以只打IMAGE ID的前三位
## 這個IMAGE ID要根據你實際build出來的映象進行修改
## 請務必執行前一條命令docker images, 找到對應的ID
docker run 2045f43c5e88
輸出如下:
Linux
amd64
5.4.72-microsoft-standard-WSL2
這段Java程式的作用就是輸出當前作業系統的環境,根據輸出可以知道博主是在WSL2
上執行docker
的。
FROM alpine
WORKDIR /root/app
COPY App.java /root/app
RUN apk add openjdk8
## 設定環境變數
ENV JAVA_HOME /usr/lib/jvm/java-1.8-openjdk
ENV PATH $PATH:$JAVA_HOME/bin
RUN javac App.java
ENTRYPOINT java App
為了便於區別兩次構建出的不同映象,我們給之前的映象打上tag
使用命令:
docker tag 2045 myapp:1.0
在build
時可以使用-t
來為映象打tag
docker build . -t myapp:2.0
再次執行命令
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
myapp 1.0 2045f43c5e88 12 hours ago 526MB
myapp 2.0 0545999c0fc0 25 hours ago 131MB
可以看到兩個映象已經被分別打上了tag
,不過值得注意的是tag
為1.0的映象體積要比2.0的大,這是為什麼?
直接將openjdk作為基礎映象會包含所有的Java語言編譯工具和庫。
多階段構建映象
其實執行Java程式只需要jre就行,我們沒有必要使用jdk作為基礎映象。但把程式打包成jar包,然後再交給docker的方式太麻煩了。
有沒有辦法實現編譯、打包、執行一體化呢?
當然是有的,簡單修改一下Dockerfile就可以了
先基於Maven映象生成jar包,最後執行在jre映象中,同時刪除已經用不到的Maven映象
首先建立一個maven專案
這是我的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>
<!-- 這裡將影響jar包的名字 -->
<groupId>org.example</groupId>
<artifactId>demoapp</artifactId>
<version>app</version>
<name>demoapp</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
<configuration>
<archive>
<!-- 指定mainClass,不指定可能導致jar包執行不成功 -->
<manifest>
<addClasspath>true</addClasspath>
<useUniqueVersions>false</useUniqueVersions>
<classpathPrefix>lib/</classpathPrefix>
<mainClass>org.example.App</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
<!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
<plugin>
<artifactId>maven-site-plugin</artifactId>
<version>3.7.1</version>
</plugin>
<plugin>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>3.0.0</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
然後在專案的根目錄下建立Dockerfile
檔案
## build stage
FROM maven:3.8.3-jdk-8 AS MAVEN_BUILD
WORKDIR /build/
# 把本地的pom.xml和src目錄複製到映象的/build目錄下
COPY pom.xml /build/
COPY src /build/src/
# 執行打包命令
RUN mvn package
## run s
FROM openjdk:8-jre-alpine
# 設定工作目錄在映象的 /app 目錄下
WORKDIR /app
# 將第一階段生成的jar包新增到第二階段的容器中
COPY --from=MAVEN_BUILD /build/target/demoapp-app.jar /app/
# 執行jar包
ENTRYPOINT java -jar demoapp-app.jar
REPOSITORY TAG IMAGE ID CREATED SIZE
<none> <none> 770d75ab38d7 7 seconds ago 84.9MB
最後生成的映象大小要比之前的500MB小了很多
Dockerfile常用命令
命令 | 描述 |
---|---|
FROM | 基礎映象 |
MAINTAINER | 維護者資訊 |
ADD | 新增檔案到映象(自動解壓) |
COPY | 新增檔案到映象(不解壓) |
USER | 設定執行RUN指令的使用者 |
ENV | 設定環境變數 |
RUN | 映象製作時執行的命令 |
ENTRYPOINT | 容器啟動時執行的命令(無法被覆蓋) |
CMD | 容器啟動時執行的命令(多條CMD只執行最後一條) |
EXPOSE | 宣告要開啟的埠(實際還是要docker run -p port1:port2 才行) |
VOLUME | 目錄對映 |
ONBUILD | 構建時自動執行的命令 |