How to configure a GlassFish instance running on AWS/ElasticBeanstalk/Docker?

后端 未结 2 1464
时光取名叫无心
时光取名叫无心 2021-01-12 04:02

I\'m using GlassFish to serve up a Java EE web app. Things are working fine on my local dev machine. I have

  • copied postgres JDBC libraries into the right place
2条回答
  •  广开言路
    2021-01-12 04:37

    What follows is something that works for me - but I have a feeling I'm missing something. Any edits/comments would be most welcome.

    There are various hooks in the EB/Docker deployment that allow execution of post-deployement hooks to be run in a glassfish instance, within a docker container, within a EB instance. I used post-deployment hooks to set up a connection pool. Here's what the final install looks like, just for reference:

    |  | |  \_WAR_/  | | |
    |  | \_Glassfish_/ | |
    |  \____Docker____/  |
    \____EC2 Instance____/
    

    The overall desired outcome is that, after the app is deployed, inside the Docker instance, the asadmin commands are run to create a JDBC connection pool, and to make that connection pool into a jdbc resource. On my local machine, the commands would be

    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
    

    Where 'jdbc/dev' is the name that the java code needs to know to get a connection in the usual manner i.e.

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

    We want the commands to run inside the docker instance, because the docker instance has access to the environment variables that you declare in the AWS admin console, so I can pass configuration information without having it in my build scripts.

    To achieve this outcome, we require that a file is created in the EC2 instance during installation, in my case called /opt/elasticbeanstalk/hooks/appdeploy/post/99_configure_jdbc.sh. This file will be executed post-deployment, as root, in the EC2 instance. I'll refer to it as the ec2-post-deploy-hook.

    We're going to create that file using a .ebextensions/.config file, as documented here

    • http://docs.aws.amazon.com/elasticbeanstalk/latest/dg/customize-containers.html
    • http://docs.aws.amazon.com/elasticbeanstalk/latest/dg/customize-containers-ec2.html

    My .config file has the following contents:

    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
    

    Everything after the content: | ends up in the ec2-post-deploy-hook.

    I learned this idea from http://junkheap.net/blog/2013/05/20/elastic-beanstalk-post-deployment-scripts.

    Only the last line and the 4th last line are needed, but the other lines are useful for debugging. Output ends up in /tmp/post on the EC2 instance.

    The one trick in that file is that we can always get the ID of the docker container by

    sudo docker ps | grep latest | cut -d" " -f1
    

    because after deployment there will only be one Docker container running, and it will have "latest" in its name.

    The last line of the ec2-post-deploy-hook uses docker to run, inside the docker instance, those commands that I originally wanted run - that is, the asadmin commands. I deploy a file called setup_pool.sh inside my .war file, so it ends up in a known location during deployment. My setup_pool.sh looks like this (and I call it a 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
    

    This file is run within in docker instance. The two asadmin commands are the meat, but again, there's some debugging into /tmp/setup_connections within the docker instance

    Passwords, etc, are obtained from the AWS environment.

    The only thing I cannot do at this point is have the AWS environment variables available on first deployment. I have no idea why, but I only seem to be able to set them after the instance is up and running. This means that I have to deploy twice, a dummy deploy, followed by an edit of the environment, followed by a real deploy.

    So, summing up,

    • at deployment
      • a .config file generates an ec2-post-deploy-hook file,
      • the AWS system deploys the docker-post-deploy-hook as a part of the .war that is deployed to glassfish
    • at post deployment,
      • the elastic beanstalk system runs the ec2-post-deploy-hook
      • the ec2-post-deploy-hook runs the docker-post-deploy-hook
      • the docker-post-deploy-hook runs asadmin to set up the appropriate connection pools
    • at run time, the Java code in the web app makes use of the connection pools

    And it all works. It's kind of ugly to behold, but, you know, so am I.

提交回复
热议问题