运行简单的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

REPOSITORYTAG都为<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 构建时自动执行的命令

Docker极简入门:使用Docker运行Java程序的更多相关文章

  1. .Net Core in Docker极简入门(下篇)

    Tips:本篇已加入系列文章阅读目录,可点击查看更多相关文章. 目录 前言 开始 Docker-Compose 代码修改 yml file up & down 镜像仓库 最后 前言 上一篇[. ...

  2. Docker极简入门:使用Docker-Compose 运行网站浏览量统计Demo

    Docker-Compose 是一个可以对 Docker 容器集群的快速编排的工具,能够减轻您心智和手指的负担. 简单的来说 Docker-Compose 就是将你运行多个容器的命令编写到了一起,类似 ...

  3. 小白的docker极简入门(二)、5分钟教你玩转docker安装

    0-前言 上一篇中,我们已经安装后Linux了,我们需要在Linux下安装docker,然后才能在docker中安装和部署各种应用 同样,5分钟教你完成docker正确安装和使用, 不是纸上谈兵,不是 ...

  4. .Net Core in Docker极简入门(上篇)

    目录 前言 开始 环境准备 Docker基础概念 Docker基础命令 Docker命令实践 构建Docker镜像 Dockerfile bulid & run 前言 Docker 是一个开源 ...

  5. Docker极简入门:使用Docker-Compose 搭建redis集群

    为了构建一个集群,我们首先要让 redis 启用集群模式 一个简单的配置文件如下redis.conf # redis.conf file port 6379 cluster-enabled yes c ...

  6. ElasticSearch极简入门总结

    一,目录 安装es 项目添加maven依赖 es客户端组件注入到spring容器中 es与mysql表结构对比 索引的删除创建 文档的crud es能快速搜索的核心-倒排索引 基于倒排索引的精确搜索. ...

  7. Spring Security极简入门三部曲(上篇)

    目录 Spring Security极简入门三部曲(上篇) 写在前面 为什么要用Spring Security 数据库设计 demo时刻 核心代码讲解 小结 Spring Security极简入门三部 ...

  8. Git 极简入门教程学习笔记

    Git 极简入门教程  http://rogerdudler.github.io/git-guide/index.zh.html 测试用 https://github.com/xxx/BrnShop. ...

  9. Spring Security极简入门三部曲(中篇)

    目录 Spring Security极简入门三部曲(中篇) 验证流程 Authentication接口 过滤器链 AuthenticationProvider接口: demo时刻 代码讲解 小结 Sp ...

随机推荐

  1. Spring 框架学习

    转载自前辈:我没有三个新脏 Spring学习(1)--快速入门 认识 Spring 框架 Spring 框架是 Java 应用最广的框架,它的成功来源于理念,而不是技术本身,它的理念包括 IoC (I ...

  2. centos7谷歌chrome内网部署演示

    上传需要的包,注释网关创建内网环境 [root@localhost ~]# ls anaconda-ks.cfg chrome mcw4 mcw4.tar.gz mcwchromerpm.tar.gz ...

  3. epoll实现快速ping

    概述 在VOIP的运营过程中,最常见的一类问题就是语音质量问题,网络间的丢包.延迟.抖动都会造成语音质量的体验下降. 当现网出现语音质量问题的时候,我们有没有工具能够快速的界定问题的边界,缩小排查的范 ...

  4. verilog specify

    specify block用来描述从源点(source:input/inout port)到终点(destination:output/inout port)的路径延时(path delay),由sp ...

  5. 【数据结构与算法Python版学习笔记】引言

    学习来源 北京大学-数据结构与算法Python版 目标 了解计算机科学.程序设计和问题解决的基本概念 计算机科学是对问题本身.问题的解决.以及问题求解过程中得出的解决方案的研究.面对一 个特定问题,计 ...

  6. 【c++ Prime 学习笔记】目录索引

    第1章 开始 第Ⅰ部分 C++基础 第2章 变量和基本类型 第3章 字符串.向量和数组 第4章 表达式 第5章 语句 第6章 函数 第7章 类 第 Ⅱ 部分 C++标准库 第8章 IO库 第9章 顺序 ...

  7. 【数据结构与算法Python版学习笔记】树——平衡二叉搜索树(AVL树)

    定义 能够在key插入时一直保持平衡的二叉查找树: AVL树 利用AVL树实现ADT Map, 基本上与BST的实现相同,不同之处仅在于二叉树的生成与维护过程 平衡因子 AVL树的实现中, 需要对每个 ...

  8. LeetCode:“剑指 Offer”

    LeetCode:"剑指 Offer" 刷题小菜鸡,花了几天时间做了一遍 LeetCode 上给出的 "剑指 Offer" 在此做一下记录 LeetCode主页 ...

  9. 第一次Alpha Scrum Meeting

    本次会议为Alpha阶段第一次Scrum Meeting会议 会议概要 会议时间:2021年4月22日 会议地点:北航Inspiration Space咖啡厅 会议时长:1小时 会议内容简介:本次会议 ...

  10. 零基础学习Linux心得总结

    很多同学接触linux不多,对linux平台的开发更是一无所知. 而现在的趋势越来越表明,作为一个优秀的软件开发人员,或计算机it行业从业人员,="" 掌握linux是一种很重要的 ...