你想在 Java EE 应用中使用Docker 吗?
一个典型的Java EE应用程序由应用服务器(例如: WildFly )和数据库(例如:Mysql)组成的。除此以外,你也许还需要一个前端负载:例如Apache,用于多台应用服务器的负载均衡,缓存:例如Infinispan,可以用于提高应用的整体性能。消息中间件:例如 ActiveMQ ,可以用于处理队列。缓存和消息组件可以用于集群的进一步扩展。
本文将先讲解一个简单 Docker 容器配置方法:包括应用服务器和数据库。接下来将讲解几个高级应用方法:包括前端负载、缓存、消息中间件和集群。
让我们开始吧!
如果你的机器之前没有安装过Docker,那么首先你需要安装Docker。你可以使用是最新版本的linux,它已经集成了Docker,或者使用安装命令:
sudo apt-get install docker-io
在Mac和windows系统上,则需安装 boot2docker ,它是一个微内核的linux虚拟机包含Docker主机。同时你需要配置ssh秘钥和证书。
幸运的是, Docker Machine . 使用非常简单。你从头开始到创建完成一个Docker主机只需要一条指令。这个主机可以创建在你的便携设备上、云端或数据中心。在多个服务器上安装Docker,Docker客户端可以传输配置。
关于这方面的详细讲解请关注: Docker Machine to Setup Docker Host .
Java EE 7 的一个很酷的功能是带默认的数据库资源。这可以让你不用担心在你的应用程序可以访问之前为应用服务器创建特定的JDBC资源。任何Java EE 7兼容的应用服务器将默认的JDBC资源名称(java:comp/defaultdatasource)映射到自带的数据库服务器内的应用服务器专用的资源上。
例如,WildFly 捆绑了 H2 内存数据库。一旦 Wildfly 准备接受请求的时候该数据库就可用了。这简化了开发工作,让你做一个快速原型。默认的 JDBC 资源映射到 java:jboss/datasources/ExampleDS,然后又会被映射到 JDBC URL ofjdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE.
这这种情况下,数据库服务器是运行在应用服务器内的另一个应用。
下面是在WildFly上运行Jave EE7应用
docker run -it -p 8080:8080 arungupta/javaee7-hol
如果你想运行一个典型的WildFly加H2内存数据库的Java EE 7应用,那么这种Docker方法的详细解释见 Java EE 7 Hands-on Lab on WildFly and Docker 。
前一种方法能够让你快速上手,但是很快出现了瓶颈-数据库只能在内存中。这就意味着你更改任何数据和 schema 在应用服务关闭后都将要失效。在这种情况下,你需要使用应用服务器意外的数据库服务器。例如,MySQL 数据库服务器和 WildFly 应用服务器。
简单起见,数据库服务器和应用程序服务器可以在同一个主机上运行。
Docker Container Links 被用来链接两个容器。在资源容器和目标容器间创建管道链接并且能够保证数据在两个容器间安全传输。 在我们的案例中,目标容器(WildFly)可以看到资源信息(MySQL)。重点需要理解是在资源容器中不需要公开任何信息,仅仅是在目标容其中可见。
启动 MySQL 和 WildFly 容器并且添加链接:
docker run --name mysqldb -e MYSQL_USER=mysql -e MYSQL_PASSWORD=mysql -e MYSQL_DATABASE=sample -e MYSQL_ROOT_PASSWORD=supersecret -d mysql docker run --name mywildfly --link mysqldb:db -p 8080:8080 -d arungupta/wildfly-mysql-javaee7
上一种方法要求你以特定的次序运行容器。如果应用程序的每一层都位于一个容器里,那么运行多容器应用程序就很快变得富有挑战性。 Fig (已被 Docker Compose 取代)是一款具有以下特征的 Docker 编排工具:
只用一个配置文件就能定义多个容器
通过在两个容器间创建 link 来建立它们之间的依赖关系
以合理的顺序启动各个容器
下面的配置文件就是 Fig 的入口:
mysqldb: image: mysql:latest environment: MYSQL_DATABASE: sample MYSQL_USER: mysql MYSQL_PASSWORD: mysql MYSQL_ROOT_PASSWORD: supersecret mywildfly: image: arungupta/wildfly-mysql-javaee7 links: - mysqldb:db ports: - 8080:8080
所有的容器可以这样来启动:
fig up -d
使用 Fig 编排 Docker 详细阐述了这种方法。
现在 Fig 只接受更新,它的代码是 Docker Compose 的基础。相关讲解参见下一种方法。
Docker Compose 是一种在Docker上定义和运行复杂应用程序的工具。通过Compose,你在单独的文件中定义一个多容器应用程序,只需执行一个命令就能让你的应用程序运行起来。
应用程序的配置文件格式和Fig所用的一致。这些容器可以这样启动:
docker-compose up -d
对这个方法的详细讲解参见 使用Docker Compose组织容器 。
在前一个方法中,两个容器运行在同一个宿主上。它们俩可以使用Docker linking方便地互相通信。但是简单的容器级linking不允许跨宿主通信。
在同一个宿主上运行容器意味着你无法扩展每一层,数据库属于独立的一层,应用服务器也属于独立的一层。在这种情况下,你需要在不同的宿主上运行每个容器。
MySQL容器可以这样启动:
docker run --name mysqldb -e MYSQL_USER=mysql -e MYSQL_PASSWORD=mysql -e MYSQL_DATABASE=sample -e MYSQL_ROOT_PASSWORD=supersecret -p 5306:3306 -d mysql
JDBC资源可以这样创建:
data-source add --name=mysqlDS --driver-name=mysql --jndi-name=java:jboss/datasources/ExampleMySQLDS --connection-url=jdbc:mysql://$MYSQL_HOST:$MYSQL_PORT/sample?useUnicode=true&characterEncoding=UTF-8 --user-name=mysql --password=mysql --use-ccm=false --max-pool-size=25 --blocking-timeout-wait-millis=5000 --enabled=true
WildFly容器可以这样启动:
docker run --name mywildfly -e MYSQL_HOST=<IP_ADDRESS> -e MYSQL_PORT=5306 -p 8080:8080 -d arungupta/wildfly-mysql-javaee7
对这个方法的完整阐述参见 在多个宿主之间使用Docker容器的linking技术 。
Docker Swarm 是Docker的原生集群管理工具。它将一群Docker宿主变为单一的虚拟宿主。通过优化宿主资源利用率,提供故障转移服务,它弥补了Docker Machine的不足。具体地说,Docker Swarm允许用户将运行着Docker守护进程的宿主组建为资源池,并在此之上调度Docker容器的运转,自动管理工作负载的分配,维护集群的状态。
关于这个方法的更多详情将在后续博客中介绍。
这个压轴方法将教你如何把已有的应用程序部署到一个Docker镜像中。
假定你将 JBoss Tools 作为你的开发环境, WildFly 用作你的应用服务器。
这里提供两条途径来部署这些应用程序:
1) 基于 Docker volumes + 本地 的部署方式:在你本地计算机上有一个目录,正以 Docker Volume 的形式挂载着。通过将这个目录映射到用于部署的目录,WildFly Docker容器被这样启动起来:
docker run -it -p 8080:8080 -v /Users/arungupta/tmp/deployments:/opt/jboss/wildfly/standalone/deployments/:rw jboss/wildfly
通过设置JBoss Tools将WAR文件部署到这个目录中。
2) 基于 WildFly管理API + 远程 的部署方式:启动WildFly Docker容器,此外还要开放管理端口9990:
docker run -it -p 8080:8080 -p 9990:9990 arungupta/wildfly-management
通过设置JBoss Tools来使用远程的WildFly服务器,并利用管理API来进行部署。
对这个方法的详细讲解在 从Eclipse部署到WildFly和Docker上 中可以找到。
Arquillian Cube 允许你以手动或自动的方式,在测试的生命周期中,控制Docker镜像的生命周期。Cube利用Docker REST API与容器通信。它使用远程适配器API同应用服务器通信,比如这里用到的WildFly。Docker参数是作为maven-surefire-plugin的一部分来配置的:
<configuration> <systemPropertyVariables> <arquillian.launch>wildfly-docker</arquillian.launch> <arq.container.wildfly-docker.configuration.username>admin</arq.container.wildfly-docker.configuration.username> <arq.container.wildfly-docker.configuration.password>Admin#70365</arq.container.wildfly-docker.configuration.password> <arq.extension.docker.serverVersion>1.15</arq.extension.docker.serverVersion> <arq.extension.docker.serverUri>http://127.0.0.1:2375</arq.extension.docker.serverUri> <arq.extension.docker.dockerContainers> wildfly-docker: image: arungupta/javaee7-samples-wildfly exposedPorts: [8080/tcp, 9990/tcp] await: strategy: polling sleepPollingTime: 50000 iterations: 5 portBindings: [8080/tcp, 9990/tcp] </arq.extension.docker.dockerContainers> </systemPropertyVariables> </configuration>
关于这个方法的完整详情可以在 使用Arquillian Cube在Docker上运行Java EE测试 中找到。
在Docker上部署你的Java EE应用程序时,你还用了什么其他方法吗?
欢迎尝试这些方法!