dockerwildfly-8dockerfileapiman

Chaining Docker Images and execute in order


I am extending the APIMan / Wildfly Docker image with my own image which will do two things:

1) Drop my .war file application into the Wildfly standalone/deployments directory

2) Execute a series of cURL commands that would query the Wildfly server in order to configure APIMan.

Initially, I tried creating two Docker images (the first to drop in the .war file and the second to execute the cURL commands), however I incorrectly assumed that the CMD instruction in the innermost image would be executed first and CMD's would be executed outward.

For example:

ImageA:
FROM jboss/apiman-wildfly:1.1.6.Final
RUN /opt/jboss/wildfly/bin/add-user.sh admin admin --silent
COPY /RatedRestfulServer/target/RatedRestfulServer-1.0-SNAPSHOT.war /opt/jboss/wildfly/standalone/deployments/

CMD ["/opt/jboss/wildfly/bin/standalone.sh", "-b", "0.0.0.0", "-bmanagement", "0.0.0.0", "-c", "standalone-apiman.xml"]

And

ImageB:
FROM ImageA
COPY /configure.sh /opt/jboss/wildfly/

CMD ["/opt/jboss/wildfly/configure.sh"]

I had initially assumed that during runtime Wildfly / APIMAN would be started first (per the ImageA CMD instruction) and then my custom script would be run (per ImageB CMD instruction). I'm assuming that's incorrect because throughout the entire hierarchy, only 1 CMD instruction is executed (the last one in the outermost Dockerfile within the chain)?

So, I then attempted to merge everything into 1 Dockerfile which would (in the build process) startup Wildfly / APIMAN, run the cURL commands, shutdown the wildfly server and then the CMD command would start it back up during runtime and Wildfly / APIMan would be configured. This, however, does not work because when I start Wildfly (as part of the build), it controls the console and waits for log messages to display, thus the build never completes. If I append an '&' at the end of the RUN command, it does not run (Dockerfile : RUN results in a No op).

Here is my Dockerfile for this attempt:

FROM jboss/apiman-wildfly:1.1.6.Final
RUN /opt/jboss/wildfly/bin/add-user.sh admin admin --silent
COPY /RatedRestfulServer/target/RatedRestfulServer-1.0-SNAPSHOT.war /opt/jboss/wildfly/standalone/deployments/
COPY /configure.sh /opt/jboss/wildfly/
RUN /opt/jboss/wildfly/bin/standalone.sh -b 0.0.0.0 -bmanagement 0.0.0.0 -c standalone-apiman.xml
RUN /opt/jboss/wildfly/configure.sh
RUN /opt/jboss/wildfly/bin/jboss-cli.sh --connect controller=127.0.0.1 command=:shutdown

CMD ["/opt/jboss/wildfly/bin/standalone.sh", "-b", "0.0.0.0", "-bmanagement", "0.0.0.0", "-c", "standalone-apiman.xml"]

Are there any solutions to this? I'm trying to have my "configure.sh" script run AFTER Wildfly / APIMan are started up. It wouldn't matter to me whether this is done during the build process or at run time, however I don't see any way to do it during the build process because Wildfly doesn't have a daemon mode.


Solution

  • The original premise behind my problem (though it was not explicitly stated in the original post) was to configure APIMan within the image and without any intervention outside of the image.

    It's a bit of a hack, but I was able to solve this by creating 3 scripts. One for starting up Wildfly, one for running the configuration script and a third to execute them both. Hopefully, this saves some other poor soul from spending a day figuring all of this out.

    Because of the nature of the Dockerfile only allowing 1 execution call at runtime, that call needed to be to a custom script.

    Below are the files with comments.

    Dockerfile

    FROM jboss/apiman-wildfly:1.1.6.Final
    RUN /opt/jboss/wildfly/bin/add-user.sh admin admin --silent
    COPY /RatedRestfulServer/target/RatedRestfulServer-1.0-SNAPSHOT.war /opt/jboss/wildfly/standalone/deployments/
    COPY /configure.sh /opt/jboss/wildfly/
    COPY /execute.sh /opt/jboss/wildfly/
    COPY /runWF.sh /opt/jboss/wildfly/
    
    CMD ["/opt/jboss/wildfly/execute.sh"]
    

    Note, all 3 scripts are built into the image. The execute.sh script is executed at runtime (instantiation) not build-time.

    execute.sh

    #!/bin/sh
    
    /opt/jboss/wildfly/configure.sh &
    /opt/jboss/wildfly/runWF.sh
    

    Note, the configure.sh script is sent to the background so that we can move on to the runWF.sh script while configure.sh is still running)

    configure.sh

    #!/bin/sh
    
    done=""
    while [ "$done" != "200" ]
    do
            done=$(curl --write-out %{http_code} --silent --output /dev/null -u username:password -X GET -H "Accept: application/json" http://127.0.0.1:8080/apiman/system/status)
            sleep 3
    done
    
    # configuration curl commands
    curl ...
    curl ...
    

    The above configure.sh script runs in a loop querying the wildfly / apiman server via curl every 3 seconds checking its status. Once it gets back an HTTP status code of 200 (representing an "up and running" state), it exits the loop and moves freely on to the configuration. Note, this should probably be made a bit 'safer' by providing another way to exit the loop (e.g. after a certain number of query's, etc.). I imagine this would give a production developer heart palpitations and I wouldn't suggest deploying it in production, however it works for the time being.

    runWF.sh

    #!/bin/sh
    
    /opt/jboss/wildfly/bin/standalone.sh -b 0.0.0.0 -bmanagement 0.0.0.0 -c standalone-apiman.xml
    

    This script simply starts up the server. The parameters bind various modules to 0.0.0.0 and directs wildfly to use the apiman standalone xml file for configuration.

    On my machine, it takes wildfly + apiman (with my custom war file) about 10-15 seconds (depending on which computer I run it on) to fully load, but once it does, the configure script will be able to query it successfully and then move on with the configuration curl commands. Meanwhile, wildfly still controls the console because it was started up last and you can monitor the activity and terminate the process with ctrl-c.