In today's rapidly evolving tech landscape, staying on top of dependencies is crucial for ensuring the security, stability, and efficiency of software projects. One popular tool in the industry is Renovate, a dependency management platform that automates updates and keeps projects up-to-date with the latest releases.
This blog talks about how we went about integrating Renovate into our workflow.
Note: While the steps outlined below are based on Bitbucket and Google Cloud, these can be adapted to the version control and cloud provider of your choice.
Understanding the Need for Dependency Management
In a world where software is built on a foundation of myriad dependencies, managing these dependencies effectively becomes paramount. Outdated dependencies can introduce security vulnerabilities, compatibility issues, and performance bottlenecks, posing significant risks to the integrity of software projects. Recognising the importance of proactive dependency management, we sought a solution that could automate the process of dependency updates while seamlessly integrating into our existing infrastructure. Having a structured, automated process to manage dependencies gives us a framework to make more frequent, manageable changes to application code as well, where required, to incorporate these dependency changes.
Enter Renovate: Automating Dependency Updates with Precision
Renovate proved to be an ideal tool in our pursuit of efficient dependency management practices. With its advanced automation features, Renovate efficiently scans project repositories, detects outdated dependencies, and generates pull requests with updated versions, all while adhering to customisable configuration rules. This streamlined process not only saves developer time but also helps ensure that projects stay up-to-date with the latest features and security patches.
Why Renovate?
While there are several tools available for the task, such as Dependabot, which is specifically designed for GitHub, we chose Renovate for its compatibility with Bitbucket, the version control tool we currently use.
By choosing Renovate, we were able to leverage its advanced automation capabilities and self-hosted nature, which enabled us to manage dependencies efficiently within our Kubernetes cluster.
Implementing Renovate in Our Infrastructure
Besides Bitbucket, which we mentioned, we use Jenkins to manage our deployments of services hosted on Kubernetes. Thus it made sense to deploy Renovate on Kubernetes as well to run our dependency checks.
Generating an App Password in Bitbucket
Renovate needs credentials to fetch code from version control, scan dependencies, and raise a PR in version control for the suggested dependency upgrades. So we can set up credentials for Renovate in Bitbucket with the following steps:
- Navigate to Bitbucket Settings: Log in to your Bitbucket account and navigate to the settings by clicking on your profile picture in the bottom-left corner and selecting "Bitbucket settings."
- Access App Passwords: In the settings menu, locate and click on "App passwords" under the "Access management" section.
- Generate New App Password: Click on the "Create app password" button to generate a new app password. Provide a label for the password to identify its purpose, such as "Renovate Integration."
- Configure Permissions: Specify the permissions required for the app password. For Renovate, we recommend granting read and write access to repositories to ensure it can fetch dependency information for updates and create pull requests.
- Generate Password: After configuring the permissions, click on the "Create" or "Generate" button to generate the app password. Make note of the generated password as it will be required for the next steps.
Creating a Kubernetes Secret for Renovate
In order to securely pass on the Bitbucket credentials to Renovate, we store it as a Kubernetes secret. That way, when it is deployed, Renovate will be able to fetch and use the Bitbucket credentials.
- Create a Secret YAML File: Using your preferred text editor, create a YAML file named
renovate-secret.yaml
to define the Kubernetes secret.
Note: This is a temporary file and should not be stored in source control.
apiVersion: v1
kind: Secret
metadata:
name: renovate-k8-secret
namespace: your-namespace
type: Opaque
data:
BITBUCKET_TOKEN: <Base64 Encoded Bitbucket App Password>
- Encode App Password: Encode the generated app password from Bitbucket into Base64 format. You can use online tools or command-line utilities like
echo -n 'your-password' | base64
to perform this encoding. - Replace Placeholder: Replace
<Base64 Encoded App Password>
in the YAML file with the Base64 encoded value of your generated app password. - Apply Secret: Apply the secret to your Kubernetes cluster by running the following command:
kubectl apply -f renovate-secret.yaml
Configuring Renovate via Kubernetes ConfigMap
We kickstarted the process by defining a Kubernetes ConfigMap to encapsulate Renovate's configuration parameters. This included specifying the repositories to be monitored for dependency updates, ensuring flexibility and scalability across our diverse project ecosystem.
apiVersion: v1
kind: ConfigMap
metadata:
name: renovate-config
namespace: your-namespace
data:
repositories: |
your-bitbucket-org/your-repo1,your-bitbucket-org/your-repo2
kubectl apply -f renovate-configmap.yaml
Deploying Renovate as a Kubernetes Deployment
With the configuration in place, we orchestrated the deployment of Renovate as a Kubernetes Deployment, ensuring scalability and resilience. By containerising Renovate using Docker, we encapsulated its functionality within a self-contained environment, facilitating seamless deployment and maintenance. This is a simplified approach using a Kubernetes manifest directly. One could also use Helm with Helm Charts if required.
apiVersion: apps/v1
kind: Deployment
metadata:
name: renovate
namespace: your-namespace
spec:
replicas: 1
selector:
matchLabels:
app: renovate
template:
metadata:
labels:
app: renovate
spec:
containers:
- name: renovate
image: renovate/renovate:latest
command: ["renovate"]
env:
- name: RENOVATE_PLATFORM
value: bitbucket
- name: RENOVATE_USERNAME
value: your-bitbucket-username
- name: RENOVATE_REPOSITORIES
valueFrom:
configMapKeyRef:
name: renovate-config
key: repositories
- name: RENOVATE_PASSWORD
valueFrom:
secretKeyRef:
name: renovate-k8-secret
key: BITBUCKET_TOKEN
kubectl apply -f renovate-deployment.yaml
Monitoring Renovate Deployment and Observing Pull Requests
Once Renovate is successfully deployed on our Kubernetes cluster, we can monitor the status of the Renovate pod and observe how it raises pull requests for the onboarded repositories.
Checking the Status of the Renovate Pod
After applying the renovate-deployment.yaml
, you can verify that the Renovate pod is running by executing the following command:
kubectl get pods -n your-namespace
You should see output indicating that the Renovate pod is running, similar to the following:
NAME READY STATUS RESTARTS AGE
renovate-xxxxxxxxx-xxxxx 1/1 Running 0 5m
Viewing the Renovate Pod Logs
To check the logs and ensure that Renovate is operating as expected, you can use the following command:
kubectl logs <renovate-pod-name> -n your-namespace
Replace <renovate-pod-name>
with the actual name of the Renovate pod. The logs will show the activity of the Renovate tool as it scans repositories and raises pull requests for dependency updates.
Example of a Pull Request Raised by Renovate
Here is an example of how a pull request (PR) raised by Renovate might look:
In this example PR, Renovate identifies an outdated dependency and suggests an update. The PR will include details such as:
- The current version of the dependency.
- The suggested updated version.
- A changelog or release notes (if available).
- Any additional information or instructions relevant to the update.
Using Jenkins to Deploy Renovate onto Our Kubernetes Cluster
To automate the execution of Renovate within our CI/CD pipeline, we leverage Jenkins's native support for Kubernetes. By configuring Jenkins to run jobs as pods within our Kubernetes cluster, we ensure that Renovate seamlessly integrates into our existing CI/CD workflows.
Configuring Jenkins Runner for Kubernetes Commands
In order to execute Kubernetes commands within our Jenkins pipeline, we need to set up a Jenkins job or runner capable of interacting with our Kubernetes cluster. Below is an example Jenkinsfile demonstrating how to execute the necessary Kubernetes commands to deploy Renovate:
pipeline {
agent any
stages {
stage('Deploy Renovate') {
steps {
script {
sh 'kubectl apply -f renovate-configmap.yaml'
sh 'kubectl apply -f renovate-deployment.yaml'
}
}
}
}
}
This Jenkinsfile defines a simple pipeline with one stage that executes the kubectl apply
commands for deploying Renovate.
We then add Renovate as a stage in our CI pipeline, to run the dependency checks and raise a PR for fixes as required, and setting thresholds for failing the pipeline when needed.
Reflecting on Our Experience with Renovate
On setting up and executing Renovate, we got to understand the various gaps and things to update in the dependencies across our application stack. Setting this up with Jenkins and Kubernetes allowed us to leverage our existing infrastructure and tooling to integrate Renovate into our workflow seamlessly.
Key Lessons Learned:
- Embracing automation has the potential to significantly improve dependency management processes.
- Integration with Kubernetes and Jenkins facilitates smoother deployment and integration.
- Prioritising proactive maintenance efforts is essential for safeguarding against security threats.
- Cultivating a culture of continuous improvement fosters resilience and adaptability.
Empowering Developers, Strengthening Software Integrity
In an era characterised by rapid technological advancement, robust dependency management solutions are paramount. Renovate (or similar tools) are a fairly common practice across the industry. By leveraging modern tools and methodologies, we are laying the foundation for a future where software is not only reliable and secure but also agile and adaptable. We invite you to join us on this journey as we navigate the possibilities of the digital age with humility and determination.