Continuous integration has become the backbone of modern agile development. The idea is simple: every time you push new code, an automated system tests it thoroughly before allowing deployment. If something breaks, you catch it early. If everything passes, your code moves forward automatically.
This guide walks you through setting up a complete continuous delivery pipeline using Jenkins and Docker. By the end, you'll have an automated system that tests your code, builds Docker images, and deploys applications—all triggered by a simple git push.
Jenkins handles the orchestration—managing when tests run, when builds trigger, and how everything connects. Docker provides the consistency—your tests run in the same environment every time, and your applications deploy exactly as expected.
The combination is powerful. You write code, push it to GitHub, and Jenkins automatically spins up a Docker container to test it. If the tests pass, Jenkins builds a fresh Docker image and pushes it to your registry. Then it can even trigger a redeployment of your running application.
👉 Get started with cloud-native DevOps on Alibaba Cloud and streamline your deployment pipeline
First, you need to deploy Jenkins itself along with worker nodes that will actually execute your builds and tests.
Create your Jenkins orchestration template with the following configuration:
yaml
jenkins:
image: 'registry.aliyuncs.com/acs-sample/jenkins:latest'
ports:
- '8080:8080'
- '50000:50000'
volumes:
- /var/lib/docker/jenkins:/var/jenkins_home
privileged: true
restart: always
labels:
aliyun.scale: '1'
aliyun.probe.url: 'tcp://container:8080'
aliyun.probe.initial_delay_seconds: '10'
aliyun.routing.port_8080: jenkins
links:
- slave-nodejs
slave-nodejs:
image: 'registry.aliyuncs.com/acs-sample/jenkins-slave-dind-nodejs'
restart: always
volumes:
- /var/run/docker.sock:/var/run/docker.sock
labels:
aliyun.scale: '1'
This template creates two services: the Jenkins master that manages everything, and a Node.js slave that runs your actual build jobs. The slave has access to Docker through the mounted socket, letting it build and push images.
Deploy the template and you'll see both services appear in your container service dashboard. Access Jenkins through the provided endpoint—you'll use the default credentials to log in initially.
Before creating build jobs, connect your slave container to Jenkins as a proper build node.
Navigate to System Settings > Manage Node > Create Node in Jenkins. Give it a memorable label like "slave-nodejs-ut"—you'll reference this label when creating build jobs. For the host, use the internal container IP address. This keeps your build environment isolated from the public internet while still letting Jenkins communicate with it.
Use the default Jenkins credentials (username and password are both "jenkins") when setting up the node connection.
Now for the interesting part: setting up a job that automatically tests your code whenever you push changes.
Create a new freestyle project in Jenkins and select your slave-nodejs-ut node as the build location. This ensures your tests run in the containerized environment you just set up.
Connect your GitHub repository in the source code management section. Point it to your repo URL and specify which branch to monitor—typically main or master.
Enable automatic triggering by checking "GitHub hook trigger for GITScm polling." This tells Jenkins to listen for webhooks from GitHub.
Over in GitHub, add the Jenkins webhook. Go to your repository's Settings > Webhooks & services > Add service and select Jenkins (Git plugin). Enter your Jenkins URL followed by /github-webhook/—something like http://your-jenkins-url.com/github-webhook/.
Now whenever you push code, GitHub pings Jenkins, which kicks off your build.
Add a build step that executes your test commands:
bash
pwd
ls
cd chapter2
npm test
Adjust these commands to match your project structure and test framework. The key is that if any command fails, the entire build fails and nothing gets deployed.
Passing tests are great, but you want to automatically create deployable artifacts too. Create a second Jenkins job that builds Docker images, but only after tests succeed.
Create another freestyle project on the same slave node. Configure the same GitHub repository, but this time add a build trigger that says "Build after other projects are built" and specify your test job name. Set it to trigger only if the build is stable.
This creates a pipeline: code push → tests run → if tests pass, image builds.
👉 Deploy container images faster with Alibaba Cloud Container Registry and reduce your build times
Add a build step with your Docker commands:
bash
cd chapter2
docker build -t registry.aliyuncs.com/your-namespace/nodejs-demo .
docker login -u ${yourAccount} -p ${yourPassword} registry.aliyuncs.com
docker push registry.aliyuncs.com/your-namespace/nodejs-demo
Replace the registry path and credentials with your own. Consider using Jenkins credentials management instead of hardcoding passwords in your build scripts.
You've got fresh Docker images building automatically, but they're not doing anything yet. Connect them to your running application with deployment triggers.
Deploy your application using a container orchestration template:
yaml
express:
image: 'registry.aliyuncs.com/your-namespace/nodejs-demo'
expose:
- '22'
- '3000'
restart: always
labels:
aliyun.routing.port_3000: express
Create a trigger in your container service that redeploys this application when called. You'll get a webhook URL.
Add one more line to your Jenkins build script:
bash
cd chapter2
docker build -t registry.aliyuncs.com/your-namespace/nodejs-demo .
docker login -u ${yourAccount} -p ${yourPassword} registry.aliyuncs.com
docker push registry.aliyuncs.com/your-namespace/nodejs-demo
curl 'https://your-container-service.com/hook/trigger?triggerUrl=xxx&secret=xxx'
That final curl command tells your container service to pull the new image and restart the application. Now your entire pipeline is connected: code push → tests → image build → automatic deployment.
When builds break at 3 AM, you want to know about it. Configure email notifications so Jenkins tells you what happened.
Install the Extended Email Notification plugin in Jenkins. Under System Management > System Settings, configure your SMTP server details. Set a system administrator email address that will appear as the sender.
In your individual Jenkins projects, add a post-build action for "Editable Email Notification." Enter recipient addresses—typically the person who committed the code or team distribution lists.
Add email triggers for different scenarios: send on build failure, send on first failure, send when build is fixed. You can customize what information gets included and even write custom email templates if the defaults don't suit you.
Step back and look at what you've created. A developer pushes code to GitHub. Within seconds, Jenkins spins up a container, runs your entire test suite, and reports the results. If everything passes, it builds a production-ready Docker image, pushes it to your registry, and triggers a rolling deployment to your live environment. All automatically, all consistently.
This pattern scales well too. Add more slave nodes for parallel builds. Create separate pipelines for different branches. Add integration tests, security scans, or performance benchmarks as additional pipeline stages.
The initial setup takes some time, but the payoff is huge. Your team can deploy multiple times per day with confidence, knowing every change has been automatically validated before reaching production.