如何配置在AWS/ElasticBeanstalk/Docker上运行的GlassFish实例?

9
我正在使用GlassFish来提供Java EE Web应用程序。在我的本地开发机上一切正常。我已经:
  • 将Postgres JDBC库复制到了正确的位置
  • 在Glassfish管理控制台中配置了连接池和JDBC资源
  • 部署了一个使用该连接的Web应用程序
  • 在浏览器中看到了结果
我试图将同样的应用程序部署到AWS Elastic Beanstalk托管的Glassfish实例上。AWS-EB使用Docker来部署Glassfish实例。我只能完成上述第三步(部署Web应用程序),对于前两步我完全不知所措。
我希望通过Web访问Glassfish管理控制台,但似乎在任何级别都无法工作。另一个选择是在本地计算机上使用glass fish “asadmin” 配置远程glass fish,但我也无法做到这一点。
如何配置托管在AWS EB上的Glassfish实例?是否可能?
我做了一些观察,但我很想得到确认或否认:
  • AWS在其CLI中有一个名为“asadmin”的命令,它与附带Glassfish的“asadmin”具有相同的名称,但除此之外似乎没有任何关系。
  • 如果连接到包含Docker和Glassfish实例的AWS EC2实例,则会发生以下事情:
    • “sudo docker ps”返回端口4848/tcp,8080/tcp,8181/tcp,并且没有映射
    • “wget localhost:8080”-连接被拒绝
    • 对于8181和4848也是如此
    • “wget localhost:80”返回Glassfish主页的Web页面
  • 在运行“docker inspect”的同一实例中,我得到了一个内部IP地址(称之为1.2.3.4),然后在该EC实例上
    • “wget 1.2.3.4:8080”(和4848、8181)都返回HTML文件
    • “wget 1.2.3.4:80”-连接被拒绝
  • 如果在Docker容器中运行bash shell,则似乎出现以下问题
    • “wget localhost:8080”(和4848、8181)都返回格式良好的页面
    • “wget localhost:80”-连接被拒绝
因此,也许我需要告诉EC2实例将本地主机转发到1.2.3.4,但当EB负载平衡器扩展它时,我该如何做到这一点。
任何建议将不胜感激。

请发布您的docker ps响应(如果可能,可以混淆IP),另外也请提供您的aws docker json清单文件。 - Usman Ismail
嗨,Usman。恐怕我不知道什么是aws docker son manifest文件。(现在我怀疑这就是我的问题...) - Burleigh Bear
我指的是Dockerrun.aws.json文件。http://docs.aws.amazon.com/elasticbeanstalk/latest/dg/create_deploy_docker_image.html - Usman Ismail
啊,抱歉。我明白了。我没有一个 - 我只是使用标准的Glassfish配置。我在昨晚(澳大利亚时间)也了解到了.ebextensions文件,这是我正在追求的东西。但是我不太确定该怎么做。我会阅读你发送的链接。谢谢。 - Burleigh Bear
2个回答

6
以下是适用于我个人的方法,但我感觉自己可能还缺少了些什么。欢迎任何修改或评论。
在EB/Docker部署中有各种钩子,允许在docker容器内的glassfish实例中执行后部署钩子。我使用了后部署钩子来设置连接池。这是最终安装的样子,仅供参考:
|  | |  \_WAR_/  | | |
|  | \_Glassfish_/ | |
|  \____Docker____/  |
\____EC2 Instance____/

总体期望的结果是,在应用程序部署后,Docker实例内运行asadmin命令来创建JDBC连接池,并将该连接池转换为jdbc资源。在我的本地机器上,这些命令如下:
asadmin create-jdbc-connection-pool 
    --datasourceclassname org.postgresql.ds.PGConnectionPoolDataSource 
    --restype javax.sql.ConnectionPoolDataSource 
    --property user=USERNAME:password=PASSWORD:serverName=DBHOST:portNumber=5432:databaseName=DBNAME 
    poolName

asadmin create-jdbc-resource --connectionpoolid poolName jdbc/dev

“jdbc/dev” 是 Java 代码需要知道的名称,以通常方式获取连接。

InitialContext ctx = new InitialContext();
ds = (DataSource)ctx.lookup("jdbc/dev");

我们希望命令在docker实例内运行,因为docker实例可以访问您在AWS管理控制台中声明的环境变量,所以我可以传递配置信息而不必将其放在我的构建脚本中。
为了实现这一目标,在安装过程中需要在EC2实例中创建一个文件,我的情况下称为 /opt/elasticbeanstalk/hooks/appdeploy/post/99_configure_jdbc.sh。该文件将在EC2实例中作为root用户在部署后执行。我们将称之为ec2-post-deploy-hook。
我们将使用一个.ebextensions/.config文件来创建该文件,文档如下: 我的.config文件内容如下:
files:
  "/opt/elasticbeanstalk/hooks/appdeploy/post/99_configure_jdbc.sh":
    mode: "000755"
    owner: root
    group: root
    content: |
      #!/bin/bash
      date > /tmp/post 2>&1
      dockerid=`docker ps | grep latest | cut -d" " -f1`
      echo $dockerid >> /tmp/post 2>&1
      docker ps >> /tmp/post 2>&1
      docker exec $dockerid /var/app/WEB-INF/classes/setup_pool.sh >> tmp/post 2>&1
content: |之后的所有内容都会出现在ec2-post-deploy-hook中。
我从http://junkheap.net/blog/2013/05/20/elastic-beanstalk-post-deployment-scripts学到了这个想法。
只需要最后一行和倒数第四行,但其他行对于调试非常有用。输出结果将出现在EC2实例上的/tmp/post目录中。
该文件中的一个技巧是我们始终可以通过以下方式获取docker容器的ID:
sudo docker ps | grep latest | cut -d" " -f1

因为在部署后只会运行一个Docker容器,并且它的名称中将带有“latest”。

ec2-post-deploy-hook的最后一行使用docker来在docker实例内运行那些我最初想要运行的命令——也就是asadmin命令。我在我的.war文件中部署了一个名为setup_pool.sh的文件,所以在部署期间它最终会出现在一个已知位置。我的setup_pool.sh看起来像这样(我称它为docker-post-deploy-hook):

dbuser=$PARAM1
dbpass=$PARAM2
dbhost=$PARAM3
dbname=$PARAM4

date > /tmp/setup_connections
echo '*********' >> /tmp/setup_connections
asadmin create-jdbc-connection-pool --datasourceclassname org.postgresql.ds.PGConnectionPoolDataSource --restype javax.sql.ConnectionPoolDataSource --property user=${dbuser}:password=${dbpass}:serverName=${dbhost}:portNumber=5432:databaseName=${dbname} ei-connection-pool >>   /tmp/setup_connections 2>&1
echo '*********' >> /tmp/setup_connections
asadmin create-jdbc-resource --connectionpoolid ei-connection-pool jdbc/dev >> /tmp/setup_connections 2>&1
echo '*********' >> /tmp/setup_connections

这个文件在docker实例内运行。两个asadmin命令是重点,但是在docker实例中有一些调试信息存储在/tmp/setup_connections中。
密码等信息从AWS环境获取。
这里唯一无法做到的是在第一次部署时使AWS环境变量可用。我不知道为什么,但似乎只能在实例启动后设置它们。这意味着我必须进行两次部署,首先是虚拟部署,然后编辑环境,最后进行真正的部署。
总结一下:
  • 部署时
    • 一个.config文件生成一个ec2-post-deploy-hook文件,
    • AWS系统将docker-post-deploy-hook作为部署到glassfish的.war的一部分部署
  • 在部署后,
    • 弹性beanstalk系统运行ec2-post-deploy-hook
    • ec2-post-deploy-hook运行docker-post-deploy-hook
    • docker-post-deploy-hook运行asadmin来设置适当的连接池
  • 在运行时,Web应用程序中的Java代码使用连接池
所有这些都可以工作。看起来有些丑陋,但是,你知道,我也是这样。

4

在自己苦苦摸索了一段时间后,我认为我终于找到了一个可以接受的解决方法(至少对我来说),具体步骤如下:

创建DockerFile并将其直接打包在WAR文件中(最高层级,不要放在任何文件夹中)。 DockerFile内容如下:

# Use the AWS Elastic Beanstalk Glassfish image
FROM        amazon/aws-eb-glassfish:4.1-jdk8-onbuild-3.5.1

# Exposes port 8080
EXPOSE      8080 4848 8181

# Install Datasource dependencies
RUN         curl -L -o /tmp/connectorj.zip https://server/path/connectorj.zip && \
            unzip /tmp/connectorj.zip -d /tmp && \
            cp /tmp/connectorj/mysql-connector-java-5.1.36-bin.jar /usr/local/glassfish4/glassfish/domains/domain1/lib/ && \
            mv /var/app/WEB-INF/classes/domain.xml /usr/local/glassfish4/glassfish/domains/domain1/config/

现在,当使用 'eb deploy' 进行部署时,将执行此 Dockerfile。
在上面的简单示例中,首先下载并设置mysql jdbc驱动程序到glassfish的lib目录中。接下来,我已经将 domain.xml (所有资源等都已设置)打包到WAR本身中,并将其移动到glassfish的域配置文件夹中,在glassfish启动时加载。

这是一个更加清晰的解决方案。一个可能的改进是执行针对asadmin可执行文件的命令来配置域,而不是替换整个domain.xml文件。依赖项可以从Maven下载,以避免使用私有存储库。 - Vova

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接