In the world of software development, deploying new features without causing disruptions is a common challenge. One effective strategy to achieve this is by using canary releases. A canary release is a deployment strategy where a small percentage of users are exposed to new features before they are rolled out to everyone. This approach allows developers to gather feedback and make necessary adjustments before the feature becomes widely available.
In this tutorial, we will explore how to implement canary releases for Express.js applications using Continuous Integration/Continuous Deployment (CI/CD) pipelines. We'll use popular tools like GitHub Actions and Kubernetes to manage deployments.
The concept of canary releases involves deploying a new version of your application to a subset of users while the rest continue to use the stable version. This allows you to monitor the performance and stability of the new features without affecting all your users.
To implement this in an Express.js application, we will:
First, ensure you have an Express.js application set up. Here's a simple example:
1const express = require('express');2const app = express();34app.get('/', (req, res) => {5res.send('Hello World!');6});78app.listen(3000, () => {9console.log('Server is running on port 3000');10});
Push your Express.js application to a GitHub repository. This will be used by GitHub Actions for CI/CD.
$ git init$ git add .$ git commit -m "Initial commit"$ git branch -M main$ git remote add origin https://github.com/yourusername/express-app.git$ git push -u origin main
Create a .github/workflows/ci.yml file in your repository to define the CI pipeline:
1name: CI23on:4push:5branches: [ main ]6pull_request:7branches: [ main ]89jobs:10build:11runs-on: ubuntu-latest1213steps:14- uses: actions/checkout@v215- name: Use Node.js16uses: actions/setup-node@v217with:18node-version: '14'19- run: npm install20- run: npm test
Create a k8s directory in your repository and add the following files:
1apiVersion: apps/v12kind: Deployment3metadata:4name: express-app5spec:6replicas: 37selector:8matchLabels:9app: express-app10template:11metadata:12labels:13app: express-app14spec:15containers:16- name: express-app17image: yourusername/express-app:latest18ports:19- containerPort: 3000
1apiVersion: v12kind: Service3metadata:4name: express-app-service5spec:6selector:7app: express-app8ports:9- protocol: TCP10port: 8011targetPort: 300012type: LoadBalancer
Create a GitHub Actions workflow for deploying canary releases:
1name: Canary Deployment23on:4push:5branches:6- main78jobs:9deploy-canary:10runs-on: ubuntu-latest11steps:12- uses: actions/checkout@v213- name: Set up Docker Buildx14uses: docker/setup-buildx-action@v115- name: Log in to Docker Hub16uses: docker/login-action@v117with:18username: ${{ secrets.DOCKER_USERNAME }}19password: ${{ secrets.DOCKER_PASSWORD }}20- name: Build and push Docker image21run: |22docker build -t yourusername/express-app:latest .23docker push yourusername/express-app:latest24- name: Deploy to Kubernetes25uses: kubernetes-deploy/action@v2.1.026with:27kubeconfig: ${{ secrets.KUBECONFIG }}28manifests: 'k8s/deployment.yaml, k8s/service.yaml'29strategy: canary30replicas: 1
To route traffic to the canary version, you can use a service mesh like Istio or configure your load balancer to direct a percentage of requests to the new deployment.
For example, with Istio:
1apiVersion: networking.istio.io/v1alpha32kind: VirtualService3metadata:4name: express-app-vs5spec:6hosts:7- express-app-service8http:9- route:10- destination:11host: express-app-service12subset: canary13weight: 1014- destination:15host: express-app-service16subset: stable17weight: 90
1apiVersion: networking.istio.io/v1alpha32kind: DestinationRule3metadata:4name: express-app-dr5spec:6host: express-app-service7subsets:8- name: canary9labels:10version: canary11- name: stable12labels:13version: stable
Monitor the performance of the canary release using tools like Prometheus and Grafana. If everything looks good, you can gradually increase the traffic to the canary version until it becomes the default.
After mastering canary releases, you might want to explore advanced logging techniques for Express.js applications. This will help you gain deeper insights into your application's behavior and performance.
Stay tuned for more tutorials on building robust and scalable Express.js applications!