Kubernetes With Bitnami and Sentry
Tutorial for Developers: build, deploy and monitor container-based applications on Kubernetes with Bitnami and Sentry.io.
Join the DZone community and get the full member experience.
Join For FreeIntroduction
No matter the size of your development team or the scale at which it operates, bugs are inevitable in software development. That's why tools that quickly identify and debug errors are critical in a continuous deployment environment. These tools also need to enable the swift deployment of patches and updates to your applications.
Sentry is a popular cloud-based framework that helps developers diagnose and fix application errors in real-time. Bitnami offers a curated catalog of secure, optimized, and up-to-date containers and Helm charts for enterprises to build and deploy applications across platforms and cloud vendors. Together, this combination gives enterprise developers all the tooling they need to create and publish applications consistently, monitor and debug errors in those running applications, and release new and improved versions on an iterative basis.
This article walks you through the process of developing a basic Node.js/Express application, deploying it on Kubernetes with Bitnami's Node.js container image and Helm chart, and monitoring errors thrown by it in real-time with Sentry.
Assumptions and Prerequisites
This guide makes the following assumptions:
- You have a Docker environment installed and configured. Learn more about installing Docker.
- You have a Docker Hub account. Register for a free account.
- You have a Sentry account. Register for a free account.
- You have a Kubernetes cluster running with Helm v3.x and kubectl installed. Learn more about getting started with Kubernetes and Helm using different cloud providers.
Step 1: Create an Express Application
Tip: If you already have an Express application, you can use that instead and skip to Step 2. If you are using a MEAN application, you may need to adapt the MongoDB connection string in the application source code as explained in our MEAN tutorial.
The first step is to create a simple Express application. Follow the steps below:
Begin by creating a directory for your application and making it the current working directory:
mkdir myapp
cd myapp
Create a package.json file listing the dependencies for the project:
JSON
x12
1{
2"name": "simple-sentry-app",
3"version": "1.0.0",
4"description": "Sentry app",
5"main": "server.js",
6"scripts": {
7"start": "node server.js"
8},
9"dependencies": {
10"express": "^4.13"
11}
12}
Create a server.js file for the Express application. This is a skeleton application that randomly returns a greeting or an error.
JSON
xxxxxxxxxx
128
1'use strict';
23// constants
4const express = require('express');
5const PORT = process.env.PORT || 3000;
6const app = express();
78// route
9app.get('/', function (req, res) {
10let x = Math.floor((Math.random() * 4) + 1);
11switch (x) {
12case 1:
13res.send('Hello, world\n');
14break;
15case 2:
16res.send('Have a good day, world\n');
17break;
18case 3:
19throw new Error('Insufficient memory');
20break;
21case 4:
22throw new Error('Cannot connect to source');
23break;
24}
25});
2627app.listen(PORT);
28console.log('Running on http://localhost:' + PORT);
Step 2: Integrate Sentry
Sentry works by logging errors using a unique application DSN. Therefore, the next step is to register your application with Sentry and obtain its unique logging DSN.
- Log in to the Sentry dashboard.
- Navigate to the "Projects" page and click "Create project".
- Select "Express" as the platform.
- Add a project name and set up alerts (optional).
- Click "Create a project" to create a new project.
- On the project quickstart page, note and copy the unique DSN for your project.
Tip: You can obtain the project DSN from the "Settings -> Projects -> Client Keys (DSN)" page at any time.
Next, revisit the application source code and integrate the Sentry Node SDK as follows:
Update the package.json file to include the Sentry Node SDK in the dependency list:
JSON
xxxxxxxxxx
113
1{
2"name": "simple-sentry-app",
3"version": "1.0.0",
4"description": "Sentry app",
5"main": "server.js",
6"scripts": {
7"start": "node server.js"
8},
9"dependencies": {
10"express": "^4.13",
11"@sentry/node": "^5.15"
12}
13}
Update the server.json file to integrate Sentry with your application. Replace the SENTRY-DSN placeholder in the script below with the unique DSN for your project, as obtained previously.
JSON
xxxxxxxxxx
137
1'use strict';
23// constants
4const express = require('express');
5const PORT = process.env.PORT || 3000;
6const app = express();
7const Sentry = require('@sentry/node');
89// define Sentry DSN
10Sentry.init({ dsn: 'SENTRY-DSN' });
1112// add Sentry middleware
13app.use(Sentry.Handlers.requestHandler());
1415// route
16app.get('/', function (req, res) {
17let x = Math.floor((Math.random() * 4) + 1);
18switch (x) {
19case 1:
20res.send('Hello, world\n');
21break;
22case 2:
23res.send('Have a good day, world\n');
24break;
25case 3:
26throw new Error('Insufficient memory');
27break;
28case 4:
29throw new Error('Cannot connect to source');
30break;
31}
32});
3334app.use(Sentry.Handlers.errorHandler());
3536app.listen(PORT);
37console.log('Running on http://localhost:' + PORT);
Tip: For more information about how Sentry integrates with Node.js and Express, refer to the official documentation.
Step 3: Create and publish a Docker image of the application
Bitnami's Node.js Helm chart can pull a container image of your Node.js application from a registry such as Docker Hub. Therefore, before you can use the chart, you must create and publish a Docker image of the application by following these steps:
Create a file named Dockerfile in the application's working directory, and fill it with the following content:
Dockerfile
xxxxxxxxxx
130
1# First build stage
2FROM bitnami/node:14 as builder
3ENV NODE_ENV="production"
45# Copy app's source code to the /app directory
6COPY . /app
78# The application's directory will be the working directory
9WORKDIR /app
1011# Install Node.js dependencies defined in '/app/packages.json'
12RUN npm install
1314# Second build stage
15FROM bitnami/node:14-prod
16ENV NODE_ENV="production"
1718# Copy the application code
19COPY --from=builder /app /app
2021# Create a non-root user
22RUN useradd -r -u 1001 -g root nonroot
23RUN chown -R nonroot /app
24USER nonroot
2526WORKDIR /app
27EXPOSE 3000
2829# Start the application
30CMD ["npm", "start"]
This Dockerfile consists of two build stages:
- The first stage uses the Bitnami Node.js 14.x development image to copy the application source and install the required application modules using npm install.
- The second stage uses the Bitnami Node.js 14.x production image and creates a minimal Docker image that only consists of the application source, modules, and Node.js runtime.
Tip: Bitnami's Node.js production image is different from its Node.js development image. The production image (tagged with the suffix prod) is based on minideb and does not include additional development dependencies. It is therefore lighter and smaller in size than the development image and is commonly used in multi-stage builds as the final target image.
Let's take a closer look at the steps in the first build stage:
- The FROM instruction kicks off the Dockerfile and specifies the base image to use. Bitnami offers several container images for Docker which can be used as base images. Since the example application used in this guide is a Node.js application, Bitnami's Node.js development container is the best choice for the base image.
- The NODE_ENV environment variable is defined so that npm install only installs the application modules that are required in production environments.
- The COPY instruction copies the source code from the current directory on the host to the /app directory in the image.
- The RUN instruction executes a shell command. It's used to run npm install to install the application dependencies.
- The WORKDIR instructions set the working directory for the image.
Here is what happens in the second build stage:
- Since the target here is a minimal, secure image, the FROM instruction specifies Bitnami's Node.js production container as the base image. Bitnami production images can be identified by the suffix prod in the image tag.
- The COPY instruction copies the source code and installs dependencies from the first stage to the /app directory in the image.
- The RUN commands create a non-root user account that the application will run under. For security reasons, it's recommended to always run your application using a non-root user account. Learn more about Bitnami's non-root containers.
- The CMD instruction specifies the command to run when the image starts. In this case, the npm start will start the application.
Build the image using the command below. Replace the DOCKER-USERNAME placeholder in the command below with your Docker account username.
docker build -t DOCKER-USERNAME/myapp:1.0 .
The result of this command is a minimal Docker image containing the application, the Node.js runtime, and all the related dependencies (including the Sentry SDK).
Log in to Docker Hub and publish the image. Replace the DOCKER-USERNAME placeholder in the command below with your Docker account username.
docker login
docker push DOCKER-USERNAME/myapp:1.0
Step 4: Deploy the Application on Kubernetes
You can now proceed to deploy the application on Kubernetes using Bitnami's Node.js Helm chart.
Deploy the published container image on Kubernetes with Helm using the commands below. Replace the DOCKER-USERNAME placeholder in the command below with your Docker account username.
Dockerfile
xxxxxxxxxx
1
1helm repo add bitnami https://charts.bitnami.com/bitnami
2helm install node bitnami/node \
3--set image.repository=DOCKER-USERNAME/myapp \
4--set image.tag=1.0 \
5--set getAppFromExternalRepository=false \
6--set service.type=LoadBalancer
Let's take a closer look at this command:
- The service.type=LoadBalancer parameter makes the application available at a public IP address.
- The getAppFromExternalRepository=false parameter controls whether the chart will retrieve the application from an external repository. In this case, since the application is already published as a container image, such retrieval is not necessary.
- The image.repository and image.tag parameters tell the chart which container image and version to pull from the registry. The values assigned to these parameters should match the image published in Step 3.
- Wait for the deployment to complete. Obtain the public IP address of the load balancer service:
kubectl get svc | grep node
Tip: See the complete list of parameters supported by the Bitnami Node.js Helm chart.
Step 5: Test Sentry Error Logging
To test the application, browse to the public IP address of the load balancer. You should randomly be presented with either a greeting or an error message, as shown in the images below:
Refresh the page a few times to generate a few errors. Then, log in to your Sentry dashboard and navigate to the project's "Issues" page. You should see a summary of the errors generated by the application, grouped by type, as shown below:
Select one of the errors to see complete details, including the actual lines of code that threw the error, the request headers, and the session details. This information is available for each error captured by Sentry.
Sentry also allows you to search for other errors of a similar nature, both within the project and across your project list. The information provided can be used to debug and identify the root cause of the error.
Once the source of an error is identified and corrected:
- A new container image of the application can be built, tagged, and published using the Bitnami Node.js container image and the Dockerfile provided in Step 3.
- The revised application image can then be deployed on Kubernetes by upgrading the Bitnami Node.js Helm chart to use the new container tag, as described in Step 4.
Of course, it's also possible to completely automate these steps; refer to the series linked below to learn about creating an automated CI pipeline with Bitnami containers and charts.
Published at DZone with permission of Vikram Vaswani. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments