Jenkins CI/CD Hands-On: Building an Automated Pipeline from Scratch
1. Why Jenkins
Jenkins is an open-source CI/CD tool. Its core purpose: after code is pushed to a Git repository, automatically run “fetch code → build → test → package → deploy”.
2. Installation
Prerequisite: Java
Jenkins requires Java 17 or 21. Newer versions (e.g., Java 26) fail to start:
wget https://get.jenkins.io/war-stable/latest/jenkins.war -O /tmp/jenkins.war
/opt/jdk-21/bin/java -jar /tmp/jenkins.war --httpPort=9090
Recommended: Docker
docker run -d \
--name jenkins \
-p 9090:8080 \
-v jenkins_home:/var/jenkins_home \
jenkins/jenkins:lts-jdk21
3. Initial Setup
Visit http://localhost:9090:
- Enter the initial password (
cat ~/.jenkins/secrets/initialAdminPassword) - Choose plugin installation (skip recommended plugins, install what you need)
- Create an admin account (remember the password!)
4. Plugins
Manage Jenkins → Plugins → Available plugins
| Plugin | Purpose |
|---|---|
| Git | Pull code from Git repos |
| Pipeline | Pipeline job type |
| Gitee | Gitee integration + Webhook trigger |
Pitfall: plugin versions may require a newer Jenkins. Upgrade Jenkins to the latest LTS:
wget https://get.jenkins.io/war-stable/latest/jenkins.war -O /tmp/jenkins.war
5. Creating a Pipeline Job
New Item → name → Pipeline → OK
pipeline {
agent any
stages {
stage('Checkout') {
steps {
git url: 'git@gitee.com:your-user/your-repo.git',
branch: 'master'
}
}
stage('Build') {
steps {
sh 'echo building && ls -la'
}
}
}
post {
success { echo '✅ Build succeeded' }
failure { echo '❌ Build failed' }
}
}
Debug tip: first run a pure debug script to verify the Jenkins environment:
pipeline {
agent any
stages {
stage('Debug') {
steps {
echo 'Pipeline works!'
sh 'echo pwd: $(pwd) && echo user: $(whoami)'
}
}
}
}
6. Gitee Credentials
Generate a personal access token at https://gitee.com/profile/personal_access_tokens (scope: projects).
Manage Jenkins → Credentials → System → Global credentials → Add Credentials
| Field | Value |
|---|---|
| Kind | Username with password |
| Username | Gitee username |
| Password | Personal access token (NOT login password) |
| ID | gitee-git |
Use it in the pipeline:
git url: 'https://gitee.com/user/repo.git',
branch: 'master',
credentialsId: 'gitee-git'
⚠️ Pitfall: the Gitee API Token credential type (added by the Gitee plugin) cannot be used for git clone. You need Username with password.
Easier: if SSH keys are configured locally, use the SSH URL — no credentials needed:
7. Auto-Trigger (Webhook + ngrok)
Gitee cannot reach localhost:9090, so expose it with ngrok:
./ngrok config add-authtoken YOUR_TOKEN
./ngrok http 9090
Steps:
- Set Jenkins URL (Manage Jenkins → System) to the ngrok address
- Job → Configure → Build Triggers → check Gitee webhook trigger
- Copy the Webhook URL shown on the page
- Gitee repo → Manage → WebHooks → Add WebHook:
- URL: the copied address
- Events: Push
Alternative: use Poll SCM with H/10 * * * * to check every 10 minutes.
8. Troubleshooting
8.1 No valid crumb (403)
Jenkins CSRF protection blocks Webhook/API requests. For test environments, remove from ~/.jenkins/config.xml:
<crumbIssuer class="hudson.security.csrf.DefaultCrumbIssuer"/>
Restart Jenkins.
8.2 Forgotten admin password
Option A: stop Jenkins → edit ~/.jenkins/users/admin/config.xml → delete the whole block:
<hudson.security.HudsonPrivateSecurityRealm_-Details>
<passwordHash>...</passwordHash>
</hudson.security.HudsonPrivateSecurityRealm_-Details>
Restart, enter any password to reset.
Option B: replace the hash directly:
python3 -c "
import bcrypt
print(bcrypt.hashpw(b'admin123', bcrypt.gensalt(10, prefix=b'2a')).decode())
"
Option C: set <useSecurity>false</useSecurity> in ~/.jenkins/config.xml, restart, create a new user, then re-enable security.
8.3 Git clone auth failure
Private repo → configure credentials (section 6); or switch to the SSH URL.
8.4 Wrong Git URL format
8.5 Hugo config not found
Jenkins cloned the wrong repo — check the git url points to the actual Hugo site repo.
9. Full Example: Auto-Building a Hugo Site
The migelan-touch repo is a Hugo site with public/ committed to Gitee. Goal: push source → auto hugo build → auto-commit public/.
pipeline {
agent any
stages {
stage('Checkout') {
steps {
git url: 'git@gitee.com:user/migelan-touch.git',
branch: 'master'
}
}
stage('Build Hugo') {
steps {
sh 'hugo'
}
}
stage('Commit Artifacts') {
steps {
sh '''
git add public/
git commit -m "auto build: $(date)" || echo "no changes"
git push origin master
'''
}
}
}
post {
success { echo '✅ Site updated' }
failure { echo '❌ Build failed' }
}
}
10. Quick Command Reference
# Start / stop Jenkins
/opt/jdk-21/bin/java -jar /tmp/jenkins.war --httpPort=9090
pkill -f jenkins.war
# Initial password
cat ~/.jenkins/secrets/initialAdminPassword
# Logs
tail -100 ~/.jenkins/logs/jenkins.log
# Reload config without restart
curl http://localhost:9090/reload
# ngrok
./ngrok http 9090
curl -s http://localhost:4040/api/tunnels | grep public_url