Oracle JET Web Applications - Automating Build, Package and Deploy (to Application Container Cloud) using a Docker Container image 36

Oracle JET Web Applications – Automating Build, Package and Deploy (to Application Container Cloud) using a Docker Container

The essential message of this article is the automation for Oracle JET application of the flow from source code commit to a running application on Oracle Application Container Cloud, as shown in this picture:

image

I will describe the inside of the “black box” (actually light blue in this picture) where the build, package and deploy are done for an Oracle JET application.

The outline of the approach: a Docker Container is started in response to the code commit. This container contains all tooling that is required to perform the necessary actions including the scripts to actually run those actions. When the application has been deployed (or the resulting package is stored in an artifact repository) the container can be stopped. This approach is very clean – intermediate products that are created during the build process simply vanish along wih the container. A fresh container is started for the next iteration.

Note: the end to end build and deploy flow takes about 2 to 3 minutes on my environment. That obviously would be horrible for a simple developer round trip, but is actually quite acceptable for this type of ‘formal’ release to the shared cloud environment. This approach and this article are heavily inspired by this article (Deploy your apps to Oracle Cloud using PaaS Service Manager CLI on Docker) on Medium by Abhishek Gupta (who writes many very valuable articles, primarily around microservices and Oracle PaaS services such as Application Container Cloud).

Note: this article focuses on final deployment of the JET application to Application Container Cloud. It would however be quite simple to modify (in fact to simplify)the build container to not deploy the final ZIP file to Application Container Cloud, but instead push the file to an artifact repository or deploy to some other type of runtime platform. It would not be very hard to take the ZIP file and create a fresh Docker Container with that file that can be deployed on Kubernetes Cluster or any Docker runtime such as Oracle Container Cloud.

The sources – including a sample JET Application – are in this GitHub repo: https://github.com/lucasjellema/webshop-portal-soaring-through-the-cloud-native-sequel .

The steps I describe in this article are:

  • preparation of the Docker Container that will do the build-package-deploy actions
  • preparation of the Oracle JET application – to be turned from a locally run, developer only client side web application into a stand-alone runnable enterprise web app with server side platform (Node with Express)
  • creation of the build script that will run inside the container and orchestrate the actions by the available tools to take the source all the way to the cloud
  • putting it all together

 

1. Preparation of the Docker Container that will do the build-package-deploy actions

The first step is the composition of the Docker Container. For this step, I have made good use of Abhishek’s article and the dockerfile he proposes in that article. I complemented Abhishek’s Dockerfiles with the tooling required for building Oracle JET applications.

A visual presentation of what the Docker Container will contain – and the steps made to put it together – is shown below:

image

Note: it is fun to bake Docker Container Images completely through a Docker file – and it is certainly convenient to share the instructions for creating a Docker Container image in the form of a Docker file. However, when the steps are complex to automated through a Docker file, there is a simple alternative: build as much of the container as you can through a Docker file. Then run the container and complete it through manual steps. Finally, when the container does what you need it to do, you can commit the state of the container as your reusable container image. And perhaps at this point, you can try to extend the Docker file with some of the manual steps, if you feel that maintaining the image will be a frequently recurring task.

The Docker build file that I finally put together is included below. The key steps:

  • the container is based on the “python:3.6.2-alpine3.6” image; this is done mainly because the PSM (Oracle PaaS Service Manager command line tool requires a Python runtime environment)
  • the apk package manager for Alpine Linux is used several times to add required packages to the image; it adds curl, zip, nodejs, nodejs-npm, bash, git and openssh
  • download and install the Oracle PSM command line tool (a Python application)
  • set up PSM for the target identity domain and user
  • install the Oracle JET Command Line tool that will be used for building the JET web application
  • copy the script build-app.sh that will be executed to run the end-to-end build-package-deploy flow

 

# extended from https://medium.com/oracledevs/quick-start-docker-ized-paas-service-manager-cli-f54eaf4ebcc7
# added npm, ojet-cli and git

FROM python:3.6.2-alpine3.6

ARG USERNAME
ARG PASSWORD
ARG IDENTITY_DOMAIN
ARG PSM_USERNAME
ARG PSM_PASSWORD
ARG PSM_REGION
ARG PSM_OUTPUT


WORKDIR "/oracle-cloud-psm-cli/"

RUN apk add --update curl && \
    rm -rf /var/cache/apk/*

RUN curl -X GET -u $USERNAME:$PASSWORD -H X-ID-TENANT-NAME:$IDENTITY_DOMAIN https://psm.us.oraclecloud.com/paas/core/api/v1.1/cli/$IDENTITY_DOMAIN/client -o psmcli.zip && \
	pip3 install -U psmcli.zip 

COPY psm-setup-payload.json
RUN psm setup -c psm-setup-payload.json

RUN apk add --update nodejs nodejs-npm
RUN apk add --update zip

RUN npm install -g @oracle/ojet-cli

RUN apk update && apk upgrade &&  apk add --no-cache bash git openssh

COPY build-app.sh .

CMD ["/bin/sh"]

Use this command to build the container:

docker build –build-arg USERNAME=”your ACC cloud username” –build-arg PASSWORD=”the ACC cloud password” –build-arg IDENTITY_DOMAIN=”your identity domain” –build-arg PSM_REGION=”us” –build-arg PSM_OUTPUT=”json” -t psm-cli .

assuming that this command is run in the directory where the docker file is located.

This will create a container and tag it as image psm-cli. When this command completes, you can find the container image by running “docker images”. Subsequently, you can run a container based on the image: “docker run –rm -it psm-cli”

 

2. Preparation of the Oracle JET application

When developing a JET (4.x) application, we typically use the Oracle JET CLI – the command line tool that helps us to quickstart a new application, create composite components, serve the application locally as we are developing it to a browser with instant update of any file changes. The JET CLI is also used to build the application for release. The result of this step is the complete set of files needed to run the JET application in the browser. In order to actually offer the JET application to end users, it has to be served from a ‘web serving’ platform component – such as nginx or a backend in Python, Java or Node. Frequently, the JET application will require some server side facilities that the backend that serves the static JET application resources can also provide. For that reason, I select a JET serving backend that I can easily leverage for these serverside facilities; for me, this is currently Node.

In order to create a self running JET application for the JET application built in the pipeline discussed in this article, I have added a simple Node & Express backend.

I have used npm to create a new Node application (npm init jet-on-node). I have next created directory bin and the file www. This file is main entrypoint into the node application that serves the JET application; it delegates most work to module app that is loaded from file app.js in the root of this Node application, path /jet-on-node .

 

SNAGHTML8be0161

All static resources that the browser can access (including the JET application) go into the folder /jet-on-node/public. Module app defines – through Express – that requests for public resources (requests not handled by one of the URL path handlers) are taken care – by serving resources from the directory /public. Module app can handle other HTTP requests – for example from the JET application – and it could also implement the backend for Server Sent Events or WebSockets. Currently is handles the REST GET request to path “/about” that returns some key data for the application:

SNAGHTML8d17d8a

The dependencies for the jet-on-node application are defined in package.json during the build process of the final application, we will use “npm install” to add the server side required node modules.

At this point, we have extended our code base with a simple landing platform for the JET application that can serve the application at runtime. All that remains is to take all content under the /web directory and copy it to the jet-on-node/public folder. Then we can run the application using “npm start” in directory jet-on-node. This will execute the start script in file package.json – which is defined as “node ./bin/www”.

 

3. Creation of the build script that will run inside the container and
orchestrate the actions

The JET build container is available. The JET application is available from a Git repository (in my example in GitHub). A number of steps are now required to go to a running application on Application Container Cloud. The first steps are shown below:

 

image

1. Clone the Git repo that contains the JET application (or pull the latest sources or a specific tag)

2. Install all modules required by the JET application – by running npm install

3. Use the Oracle JET command line utility to build the application for release: ojet build –release

After this step, all run time artifacts – including the JET libraries – are in the /web directory. These next steps turn these artifacts into a running application:

4. Copy the contents of /web to /jet-on-node/public

5. Install the modules required for the server side Node application by running npm install in directory jet-on-node

6. Create a single zip file for all artifacts in the /jet-node directory – that includes both the JET application and its server side backend Node application. This zip-file is the release artifact for the JET application. As such, it can be pushed to an artifact repository or deployed to some other platform.

7. Engage psm command line interface (Oracle PaaS Service Manager CLI) to perform deployment of the zip file to the Application Container Cloud for which psm already as configured during the creation of the build container.

Note: the files manifest.json and deployment.json in the root of jet-on-node provide instructions to PSM and Application Container Cloud regarding the run time settings for this application – including the runtime version of Node, the command for starting the application, the runtime memory per instance and the number of instances as well as the values of environment variables to be passed to the application.

image

The shell-script build-app.sh (you may have to explicitly make this script executable, using “chmod u+x build-app.sh”) performs the steps described above (although perhaps not in the optimal way – feel free to fine tune and improve and let me know about it).

#git clone https://github.com/lucasjellema/webshop-portal-soaring-through-the-cloud-native-sequel
# cd webshop-portal-soaring-through-the-cloud-native-sequel

git pull
wait

npm install
wait
ojet build --release
wait
cp -a ./web/. ./jet-on-node/public
wait
cd jet-on-node
wait
npm install
wait
zip -r webshop.zip .
wait
cd /oracle-cloud-psm-cli/webshop-portal-soaring-through-the-cloud-native-sequel/jet-on-node

psm accs push -n SoaringWebshopPortal -r node -s hourly -d deployment.json -p webshop.zip

The end-to-end flow through the build container during the release of the latest version of the JET application can now be depicted like this:

image

 

4. Putting it all together

I will now try to demonstrate how this all works together. In order to do so, I will go through these steps – and illustrate them with screenshots:

  • make a change in the JET application
  • commit and push the change (to GitHub)
  • run the Docker build container psm-cli
  • run the script build-app.sh
  • wait for about three minutes (check the output in the build container and the application status in the ACC console)
  • access the updated Web Application

The starting point for the application:

SNAGHTML8fbfc34

1. Make a change

The word Shopping Basket – next to the icon – seems superfluous, I will remove that. And I will increase the version number, from v1.2.0 to v1.2.1.

image

 

2. commit and push the change (to GitHub)

image

The change is accepted in GitHub:

image

 

3. Run the Docker build container psm-cli

Run the Docker Quickstart Terminal (I am on Windows) and perform: “docker run –rm -it psm-cli”

image

 

At this point, I lack a little bit of automation. The manual step I need to take (just the first time round) is to clone the JET application’s Git repository:

git clone https://github.com/lucasjellema/webshop-portal-soaring-through-the-cloud-native-sequelCloning

and to move to the created directory

cd webshop-portal-soaring-through-the-cloud-native-sequel/

and to make the file build-app.sh executable:

chmod u+x build-app.sh

image

Note: As long the container keeps running, I only have to run “git pull” and “./build-app.sh” for every next update to the JET application. The next step would be to configure a web hook that is triggered by the relevant commit in the GitHub repository.

 

4. run the script build-app.sh

./build-app.sh

image

wait for about three minutes (check the output in the build container

image

SNAGHTML91173de

and the application status in the ACC console)

SNAGHTML90fc3cd

SNAGHTML90fe186

 

5. access the updated Web Application

image

As you can see, after committing and pushing the change, I only had to run a simple command line command to get the application fully rebuilt and redeployed. After stopping the Docker container, no traces remain of the build process. And I can easily share the container image with my team members to build the same application or update to also build other or additional JET applications.

 

Resources

The inspirational article by Abhishek Gupta: https://medium.com/oracledevs/quick-start-docker-ized-paas-service-manager-cli-f54eaf4ebcc7

The sources – including a sample JET Application – are in this GitHub repo: https://github.com/lucasjellema/webshop-portal-soaring-through-the-cloud-native-sequel .

Oracle JET Command Line Interface: https://github.com/oracle/ojet-cli

Docs on the Oracle PSM (PaaS Service Manager) CLI: https://docs.oracle.com/en/cloud/paas/java-cloud/pscli/abouit-paas-service-manager-command-line-interface.html

Node & Express Tutorial Part 2: Creating a skeleton website: https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/skeleton_website

Serving Public Files with Express – https://expressjs.com/en/starter/static-files.html

Documentation for Oracle Application Container Cloud: https://docs.oracle.com/en/cloud/paas/app-container-cloud/dvcjv/getting-started-oracle-application-container-cloud-service.html