There is exciting news for those who develop FlexDeploy plugins. So exciting, we’re adding another post to our FlexDeploy Loves Containers Blog series.
- FlexDeploy Loves Containers: Build and Deploy Microservices to Kubernetes Clusters in the Cloud
- Enrich Oracle Container Native Application Development Platform with FlexDeploy Pipelines
- FlexDeploy Loves Functions: Deploy Docker Containers with Fn Functions
- FlexDeploy Loves Functions: Build Docker Containers with Fn Functions
- FlexDeploy is a Container: Run FlexDeploy as a Docker Container
- FlexDeploy Loves Containers: Build FlexDeploy Plugins with Docker
In addition to the regular Java implementation, a plugin can be implemented as a custom Docker Image. While executing a workflow, FlexDeploy creates a Docker container out of the image, invokes the plugin’s operation, returns the result and removes the container from the endpoint. The endpoint can be a simple Docker host (having just Docker runtime installed) or it can be a Kubernetes cluster.
This concept, “Plugin as a Container” (PaaC), gives plugin developers a real freedom in terms of tools and technologies they can use to enrich FlexDeploy with their custom functionality. Furthermore, in a way it makes them independent from the infrastructure. A plugin container can be packaged with all necessary tools, libraries and drivers, meaning that it can run everywhere, on any endpoint having Docker engine installed, so there is no need to install anything else.
FlexDeploy comes with two containerized plugins today – Oracle ADF Builder and SOAP UI Docker. Oracle ADF Builder plugin has preinstalled JDeveloper 12.1.3 so it can build ADF applications everywhere, even in the cloud on a K8s cluster. Same is true about SOAP UI Docker plugin which has SOAP UI in the plugin container installed and capable of running SOAP tests from any endpoint with Docker engine.
In this post we’re going to create a new FlexDeploy plugin to build Oracle Jet applications. The key point is that it is extremely easy.
Let’s name our new plugin OJetBuilder. First of all, I am going to create a Docker image having OJet CLI installed and serving as an actual builder. The Dockerfile for the image looks like this:
FROM node RUN npm install -g @oracle/ojet-cli COPY buildWeb.sh /usr/local/bin/buildWeb
So, we are building our image on top of node.js Docker image, installing OJet CLI and adding buildWeb.sh that actually does the job:
#!/bin/bash cd /fd_working_dir/temp/$FDOJETBUILD_WORKSPACE ojet restore ojet build web $FDOJETBUILD_OPTION cp -r web/* /fd_working_dir/artifacts/
The script goes to the folder with source code, execute OJet CLI commands building the application and returns the result web folder to the artifact directory. FlexDeploy will pick up everything from that directory and it will put it to the artifact repository.
Let’s build the image with name flexdeploy/plugin-ojetbuilder:5.0.1 and push it to Docker Hub:
docker build . -t flexdeploy/plugin-ojetbuilder:5.0.1 docker push flexdeploy/plugin-ojetbuilder:5.0.1
Having done that I am going to create a descriptor of our plugin:
<?xml version="1.0" encoding="UTF-8"?> <PluginDefinition xmlns="https://flexagon.com/deploy/plugin"> <Name>FlexagonOJetBuilderPlugin</Name> <PluginDisplayName>Oracle Jet Builder</PluginDisplayName> <Description>A plugin to build Jet applications.</Description> <TechnologyGroup>Build</TechnologyGroup> <SubTechnologyGroup>Jet</SubTechnologyGroup> <MaxConcurrentThreads>3</MaxConcurrentThreads> <Type>docker</Type> <ImageName>flexdeploy/plugin-ojetbuilder</ImageName> <Vendor>Flexagon</Vendor> <Version>5.0.1</Version> <Operations> <Operation> <Name>buildWeb</Name> <Description>Build Ojet Web application</Description> <Target>buildWeb</Target> <ProducesArtifacts>true</ProducesArtifacts> <ConsumesArtifacts>false</ConsumesArtifacts> <Outputs> <AllowsUserDefined>false</AllowsUserDefined> </Outputs> <Inputs> <AllowsUserDefined>false</AllowsUserDefined> <Input> <Name>FDOJETBUILD_WORKSPACE</Name> <DisplayName>Workspace Name</DisplayName> <IsDefaultValueExpression>false</IsDefaultValueExpression> <DataType>String</DataType> <DisplayRows>1</DisplayRows> <DisplayColumns>100</DisplayColumns> <Description>Specify workspace name.</Description> <IsRequired>false</IsRequired> <IsEncrypted>false</IsEncrypted> </Input> <Input> <Name>FDOJETBUILD_OPTION</Name> <DisplayName>Options</DisplayName> <IsDefaultValueExpression>false</IsDefaultValueExpression> <DataType>String</DataType> <DisplayRows>1</DisplayRows> <DisplayColumns>100</DisplayColumns> <Description>Options to pass to ojet build</Description> <IsRequired>false</IsRequired> <IsEncrypted>false</IsEncrypted> </Input> </Inputs> <EndPointSpecification> <Selection> <All/> </Selection> <Execution> <Any/> </Execution> </EndPointSpecification> </Operation> </Operations> </PluginDefinition>
It looks like a regular plugin.xml file. The only thing is that plugin type is docker and there is a reference to Docker image in the ImageName tag. As in case with a regular Java-based plugin we are going to create a jar file to upload the plugin to FlexDeploy. The jar file contains a single plugin.xml file. So, in folder with plugin.xml we are executing the following:
jar cvfM0 FlexagonOJetBuilderPlugin-5.0.1.jar *
This will create a jar file that FlexDeploy is capable to download as a plugin:
Ok, it looks like the plugin is in place. Let’s use it in FlexDeploy. Plugins of this type can run on either “Docker Host” or “K8s cluster” endpoints:
- Docker Host. An endpoint with Docker engine installed.
- K8s cluster. An endpoint with kubectl installed and configured to communicate with a K8s cluster.
For example I have an endpoint with kubectl talking to a K8s cluster in Oracle Cloud Infrastructure:
When FlexDeploy is invoking a plugin operation on this endpoint the job will be actually done in a Docker container running in a K8s cluster.
The workflow with our new plugin looks like this one:
Where the buildWeb step is invoking the buildWeb operation of Oracle Jet Builder plugin:
I told you that would be easy.