# Docker容器中怎么使用Jenkins部署Web項目
## 前言
在當今DevOps實踐中,持續集成和持續部署(CI/CD)已成為現代軟件開發的核心環節。Jenkins作為最流行的開源自動化服務器,與Docker容器化技術的結合,為Web項目部署提供了高效、可靠的解決方案。本文將詳細介紹如何在Docker環境中使用Jenkins實現Web項目的自動化部署,涵蓋從環境搭建到高級配置的全流程。
## 第一章:環境準備與基礎概念
### 1.1 Docker與Jenkins概述
**Docker**是一種輕量級的容器化技術,它允許開發者將應用及其依賴打包到標準化的單元中,實現"一次構建,隨處運行"的目標。與傳統虛擬機相比,Docker容器更加輕量、啟動更快且資源占用更少。
**Jenkins**是一個用Java編寫的開源自動化服務器,提供了數百個插件支持構建、部署和自動化任何項目。其主要特點包括:
- 易于安裝和配置
- 豐富的插件生態系統
- 分布式構建能力
- 強大的流水線(Pipeline)支持
### 1.2 為什么要在Docker中使用Jenkins?
將Jenkins運行在Docker容器中具有以下優勢:
1. **環境隔離**:Jenkins及其依賴被封裝在容器中,與主機系統隔離
2. **快速部署**:通過Docker鏡像可以快速部署Jenkins實例
3. **易于維護**:升級或回滾只需更換鏡像版本
4. **資源可控**:可以限制容器使用的CPU、內存等資源
5. **可移植性**:相同的配置可以在不同環境中運行
### 1.3 系統要求
在開始之前,請確保您的系統滿足以下要求:
- **操作系統**:Linux/Windows/macOS(推薦Linux)
- **Docker**:版本20.10.0或更高
- **Docker Compose**:版本1.29.0或更高(可選但推薦)
- **硬件**:
- 至少4GB RAM(建議8GB以上)
- 至少20GB可用磁盤空間
- 2核CPU或更多
## 第二章:安裝與配置Docker環境
### 2.1 安裝Docker引擎
根據不同操作系統,安裝步驟略有差異:
#### Ubuntu/Debian系統
```bash
# 卸載舊版本
sudo apt-get remove docker docker-engine docker.io containerd runc
# 安裝依賴
sudo apt-get update
sudo apt-get install \
apt-transport-https \
ca-certificates \
curl \
gnupg \
lsb-release
# 添加Docker官方GPG密鑰
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
# 設置穩定版倉庫
echo \
"deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# 安裝Docker引擎
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io
# 驗證安裝
sudo docker run hello-world
# 卸載舊版本
sudo yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine
# 安裝必要工具
sudo yum install -y yum-utils
# 設置倉庫
sudo yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo
# 安裝Docker引擎
sudo yum install docker-ce docker-ce-cli containerd.io
# 啟動Docker
sudo systemctl start docker
# 驗證安裝
sudo docker run hello-world
Docker Compose是一個用于定義和運行多容器Docker應用的工具,推薦安裝:
# 下載最新穩定版
sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
# 賦予執行權限
sudo chmod +x /usr/local/bin/docker-compose
# 創建符號鏈接(可選)
sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
# 驗證安裝
docker-compose --version
為避免每次使用docker命令都需要sudo,可以將當前用戶加入docker組:
sudo groupadd docker
sudo usermod -aG docker $USER
newgrp docker # 刷新組權限
# 驗證配置
docker run hello-world
Jenkins官方提供了Docker鏡像,可以直接使用:
# 拉取最新LTS版本
docker pull jenkins/jenkins:lts
# 運行Jenkins容器
docker run -d \
--name jenkins \
-p 8080:8080 \
-p 50000:50000 \
-v jenkins_home:/var/jenkins_home \
jenkins/jenkins:lts
參數說明:
- -d
:后臺運行容器
- --name
:指定容器名稱
- -p
:端口映射(8080為Web界面,50000為代理通信)
- -v
:數據卷掛載,持久化Jenkins數據
對于生產環境,推薦使用docker-compose.yml文件定義服務:
version: '3.8'
services:
jenkins:
image: jenkins/jenkins:lts
container_name: jenkins
restart: unless-stopped
ports:
- "8080:8080"
- "50000:50000"
volumes:
- jenkins_home:/var/jenkins_home
- /var/run/docker.sock:/var/run/docker.sock # 允許容器內使用Docker命令
environment:
- TZ=Asia/Shanghai
networks:
- jenkins-net
volumes:
jenkins_home:
networks:
jenkins-net:
driver: bridge
啟動服務:
docker-compose up -d
http://localhost:8080
或 http://<服務器IP>:8080
docker logs jenkins
或查看指定文件:
docker exec jenkins cat /var/jenkins_home/secrets/initialAdminPassword
配置全局安全:
設置CSRF保護:
配置代理(如果需要):
進入”Manage Jenkins” > “Manage Plugins” > “Available”,搜索并安裝以下插件:
安裝完成后重啟Jenkins。
docker --version
我們以一個簡單的Node.js應用為例:
項目結構:
my-web-app/
├── app.js
├── package.json
├── Dockerfile
└── Jenkinsfile
app.js:
const express = require('express')
const app = express()
const port = 3000
app.get('/', (req, res) => {
res.send('Hello World from Dockerized Node.js app!')
})
app.listen(port, () => {
console.log(`App listening at http://localhost:${port}`)
})
package.json:
{
"name": "my-web-app",
"version": "1.0.0",
"description": "Sample Node.js web app",
"main": "app.js",
"scripts": {
"start": "node app.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"dependencies": {
"express": "^4.17.1"
}
}
Dockerfile:
FROM node:14-alpine
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD ["npm", "start"]
Jenkinsfile (聲明式Pipeline):
pipeline {
agent {
docker {
image 'node:14-alpine'
args '-v /var/run/docker.sock:/var/run/docker.sock'
}
}
stages {
stage('Checkout') {
steps {
git branch: 'main', url: 'https://github.com/your-repo/my-web-app.git'
}
}
stage('Build') {
steps {
sh 'npm install'
}
}
stage('Test') {
steps {
sh 'npm test'
}
}
stage('Build Docker Image') {
steps {
script {
dockerImage = docker.build("my-web-app:${env.BUILD_ID}")
}
}
}
stage('Deploy') {
steps {
script {
docker.withRegistry('https://registry.hub.docker.com', 'docker-hub-credentials') {
dockerImage.push()
}
// 停止并移除舊容器
sh 'docker stop my-web-app || true'
sh 'docker rm my-web-app || true'
// 運行新容器
sh 'docker run -d --name my-web-app -p 3000:3000 my-web-app:${env.BUILD_ID}'
}
}
}
}
post {
always {
echo 'Cleanup workspace'
deleteDir()
}
success {
echo 'Deployment succeeded!'
}
failure {
echo 'Deployment failed!'
}
}
}
修改Deploy階段:
stage('Deploy') {
steps {
script {
// 確定當前運行的顏色
def runningColor = sh(script: 'docker ps -f name=my-web-app --format "{{.Names}}" | grep -o "green\\|blue" || echo "blue"', returnStdout: true).trim()
def newColor = runningColor == 'blue' ? 'green' : 'blue'
// 構建帶顏色的鏡像標簽
dockerImage = docker.build("my-web-app:${env.BUILD_ID}-${newColor}")
// 推送鏡像
docker.withRegistry('https://registry.hub.docker.com', 'docker-hub-credentials') {
dockerImage.push()
}
// 啟動新容器
sh "docker run -d --name my-web-app-${newColor} -p ${newColor == 'blue' ? '3000' : '3001'}:3000 my-web-app:${env.BUILD_ID}-${newColor}"
// 更新負載均衡或代理配置
// 這里需要根據你的基礎設施進行調整
// 可能是更新Nginx配置或Service Mesh規則
// 停止舊容器
sh "docker stop my-web-app-${runningColor} || true"
sh "docker rm my-web-app-${runningColor} || true"
}
}
}
stage('Canary Deploy') {
steps {
script {
// 構建鏡像
dockerImage = docker.build("my-web-app:${env.BUILD_ID}")
// 推送鏡像
docker.withRegistry('https://registry.hub.docker.com', 'docker-hub-credentials') {
dockerImage.push()
}
// 部署金絲雀版本(例如10%流量)
sh 'docker run -d --name my-web-app-canary -p 3001:3000 -e TRAFFIC_WEIGHT=0.1 my-web-app:${env.BUILD_ID}'
// 運行自動化測試驗證金絲雀版本
// ...
// 如果驗證通過,全量部署
sh 'docker stop my-web-app-production || true'
sh 'docker rm my-web-app-production || true'
sh 'docker run -d --name my-web-app-production -p 3000:3000 my-web-app:${env.BUILD_ID}'
// 清理金絲雀
sh 'docker stop my-web-app-canary || true'
sh 'docker rm my-web-app-canary || true'
}
}
}
Jenkins Configuration as Code (JCasC)插件允許通過YAML文件配置Jenkins:
jenkins.yaml
:jenkins:
systemMessage: "Jenkins configured automatically by Configuration as Code"
securityRealm:
local:
allowsSignup: false
users:
- id: admin
password: ${JENKINS_ADMIN_PASSWORD}
authorizationStrategy:
globalMatrix:
permissions:
- "Overall/Administer:admin"
- "Overall/Read:authenticated"
unclassified:
location:
url: "http://jenkins.example.com/"
adminAddress: "admin@example.com"
tool:
git:
installations:
- name: Default
home: /usr/bin/git
credentials:
system:
domainCredentials:
- credentials:
- usernamePassword:
scope: SYSTEM
id: docker-hub-credentials
username: ${DOCKER_HUB_USERNAME}
password: ${DOCKER_HUB_PASSWORD}
environment:
- JENKINS_ADMIN_PASSWORD=securepassword
- DOCKER_HUB_USERNAME=yourusername
- DOCKER_HUB_PASSWORD=yourpassword
- CASC_JENKINS_CONFIG=/var/jenkins_home/jenkins.yaml
volumes:
- ./jenkins.yaml:/var/jenkins_home/jenkins.yaml
創建Docker代理模板:
在Pipeline中指定標簽:
pipeline {
agent {
label 'docker-agent'
}
// ...
}
stage('Build on Dynamic Agent') {
steps {
script {
// 啟動臨時構建容器
def builder = docker.build('my-builder-image', '--build-arg ENV=production .')
// 在容器內執行構建
builder.inside {
sh 'make all'
}
}
}
}
Docker構建緩存:
Jenkins執行器配置:
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。