Implementing CI/CD in Oracle APEX using Jenkins and Autonomous Database

Implementing CI/CD in Oracle APEX using Jenkins and Autonomous Database

In the majority of projects I have undertaken, release and regression have consistently posed challenges. By implementing Continuous Integration/Continuous Deployment (CI/CD), it is possible to minimize the risks of regression and other release-related errors.

To optimize the development process and ensure a seamless workflow, the incorporation of CI/CD practices is essential. In this article, we will delve into the integration of CI/CD into an Oracle APEX project using complimentary tools available in OCI. The Application Lifecycle Management technical paper, which was published earlier, serves as the basis for this article. The paper can be accessed here.

This article is the first installment in a series of blog posts. We will begin by discussing the requirements and setup, and in subsequent posts, we will examine the actual process of executing the scripts.

Understanding CI/CD

Continuous Integration (CI) and Continuous Deployment (CD) are DevOps practices that automate the software development lifecycle. CI involves regularly merging code changes into a shared repository, enabling early bug detection. CD extends this by automating the deployment process, ensuring a continuous flow from development to production. These practices enhance collaboration, reduce integration problems, and speed up delivery, allowing developers to consistently deliver high-quality software with efficiency and reliability.

Development approach

The technical paper distinguishes two development approaches: team-centric and feature-centric development.

"In a team-centric approach, colleagues work on assigned tasks directly in the shared APEX development environment. An issue "ticket" number like app-1234 identifies each work item. Periodically, the team's progress is exported to a Git work area, committed, and pushed to the permanent team repository. Most developers on the team don't need to directly interact with the file artifacts since another team member playing the role of a build manager adds their work to the Git repository. This approach works well for smaller teams. By design, each Git commit reflects the changes the whole team has made since the previous checkpoint. However, the more developers contributing to the team effort, the more challenging it becomes to review changes made for a particular feature or by a particular developer
With a feature-centric development approach, each colleague works on one bug or feature at a time in a private work area using a private APEX instance where they are the only developer making changes. They work as long as necessary to complete their task and testing. Before submitting their changes for peer review, they update their private area to merge in any approved changes colleagues have made to application artifacts in the meantime. This proactively ensures any conflicts with their own changes get resolved. When ready, they submit their changes for peer review."

This blog will demonstrate the team-centric approach. In a later blog I'll show the feature-centric approach.

Installing requirements

To run the example we need the following tools:

  • Github

  • Compute instance

  • Autonomous Database with APEX

  • Jenkins

Setup compute instance, Jenkins & Utils

I'll assume you've a Git repo and we'll start with setting up a compute instance in OCI. In the console navigate to compute > instances, here you can click on the "Create instance" button.

  1. Give the instance a name, i.e. CI-CD VM

  2. Select your image and shape

    a. when using the free tier you only have one option: VM.Standard.E2.1.Micro. With 1 CPU and 1GB of memory this lacks resources to run smoothly in my opinion, but it's possible to use.

    b. I recommend to use the (paid) AMD shape: VM.Standard.E4.Flex

  3. Generate and download the SSH key pair

  4. Create the instance

  5. After the instance is created, we need to allow connection from anywhere. Click the VCN link in the Instance details

  6. Navigate to security list by clicking security lists and then default security list for vcn-...

  7. Add ingress rule with the following parameters. The 0.0.0.0/0 means the source can be any ip adress

  8. Return to the instance. Here you'll see the following. Copy the IP adress.

  9. Connecting to the instance can be achieved in diffent ways. I'll be using the VS Code extension Remote - SSH, but you can also use tools like Putty

  10. The extension uses a config file saved on your local machine. Copy the IP adress to the hostname and add the path to the saved private key to the IdentityFile parameter. The host parameter can be used freely

    Host CI-CD VM
      Hostname {IP-adress}
      User opc
      IdentityFile {path to SSH private key}
    
  11. Connect to the instance

  12. Install java

    sudo yum install java-17-openjdk
    
  13. Add jenkins repo

    sudo wget -O /etc/yum.repos.d/jenkins.repo https://pkg.jenkins.io/redhat-stable/jenkins.repo
    
  14. Add the Jenkins key (the 2024 isn't available yet)

    sudo rpm --import https://pkg.jenkins.io/redhat-stable/jenkins.io-2023.key
    
  15. Install, enable and start Jenkins

    sudo yum install jenkins
    sudo systemctl enable jenkins
    sudo systemctl start jenkins
    
  16. Add firewall rule, so you can access the webportal from your local machine

    YOURPORT=8080
    PERM="--permanent"
    SERV="$PERM --service=jenkins"
    
    firewall-cmd $PERM --new-service=jenkins
    firewall-cmd $SERV --set-short="Jenkins ports"
    firewall-cmd $SERV --set-description="Jenkins port exceptions"
    firewall-cmd $SERV --add-port=$YOURPORT/tcp
    firewall-cmd $PERM --add-service=jenkins
    firewall-cmd --zone=public --add-service=http --permanent
    firewall-cmd --reload
    
  17. Browse to http://{IP-adress}:8080. It can take a while before Jenkins is ready to be used (especially when using the free tier)

  18. Get the adminpassword and paste this in the browser

    sudo cat /var/lib/jenkins/secrets/initialAdminPassword
    
  19. Install the suggested plugins

  20. Create the admin user by using the wizzard

Now you're ready to use the compute instance with jenkins. Now we can install the utillities needed to run the pipelines

  1. install Git
sudo yum install git -y
  1. install SQLcl
sudo yum install sqlcl -y
  1. Set JAVA_HOME variable for SQLcl

     export JAVA_HOME=$(readlink -f $(which java) | sed "s:bin/java::")
    

Create a Jenkins Agent

A Jenkins agent is a system that Jenkins can use to execute build jobs. This system can be the same machine as the Jenkins server or a different machine. The agent allows Jenkins to offload build projects from the master server, thus distributing the workload. This can be beneficial in large-scale projects where multiple builds are running concurrently, or in projects where builds require different environments or specific system configurations. To run a Jenkins agent, we first need to create one. Execute the commands below to create such an agent. A big thanks to Matthew Mulvaney from Pretius UK and his blog [1], where I got most of the commands

  1. Disable the (default) built-in node
    → Dashboard > Manage Jenkins > Nodes > Build-In Node > Configure > Number of executors > set 0

  2. Create new Node
    → Dashboard > Manage Jenkins > Nodes > New Node

  3. Add Node Name (this example uses testNode) and select Permanent Agent

  4. Set the remote root directory to

     /home/opc/testNode
    
  5. Select Use Websocket

  6. Save and open the testNode. Here you'll find different commands we need in the next steps

  7. Open the terminal and create a directory

     mkdir /home/opc/testNode
     cd /home/opc
    
  8. Run the first command form the Unix commands

  9. To auto-load on reboot create a new file like this

     sudo nano /etc/systemd/system/jenkins-ci-cd-node.service
    
  10. Paste in the following. Don't forget to import the second command from the Unix commands

    [Unit]
    Description=Jenkins CICD Node agent
    After=syslog.target
    
    [Service]
    Type=simple
    User=opc
    ExecStart=/usr/bin/java -jar /home/opc/agent.jar -jnlpUrl [PASTE IN FROM LINE TWO STARTING WITH http:// AND ENDING WITH THE END OF THE CODE BOX]
    Restart=always
    RestartSec=30
    
    [Install]
    WantedBy=multi-user.target
    
  11. Enable, start and check the service

    sudo systemctl enable jenkins-cicd-node.service
    sudo systemctl start jenkins-cicd-node.service
    sudo systemctl status jenkins-cicd-node.service
    
  12. Refresh and check if the agent is connected

Create Autonomous Database with APEX

In the OCI console, navigate to Oracle Database > Autonomous Database > Create Autonomous Database. Here, we'll create a new database.

  1. Change the display name and database name to be more descriptive. This will help later on.

  2. Select Transaction Processing or APEX as the workload type. I prefer the transaction type.

  3. Set the admin credentials.

  4. Create the database.

  5. When the database is available, download the database client credentials. We need the zip to connect from the compute instance.

We now have installed all the requirements to start building an application and pipeline.

Part II of this blog series will dive into how to manage/organize your application code.
Part III will delve into creating the pipeline to test and install your application into another environment.