详细介绍在ubuntu 22.04上使用gitlab和jenkins部署ci/cd的完整过程。
环境准备
1. 系统初始化
# 更新系统 sudo apt update && sudo apt upgrade -y # 安装必要工具 sudo apt install -y curl wget git vim
2. 安装docker(推荐方式)
# 安装docker sudo apt install -y docker.io docker-compose sudo systemctl enable docker sudo systemctl start docker # 将当前用户添加到docker组 sudo usermod -ag docker $user
第一部分:gitlab安装与配置
1. 使用docker安装gitlab
# 创建gitlab数据目录
sudo mkdir -p /srv/gitlab/{config,data,logs}
# 创建docker-compose.yml
cat > docker-compose-gitlab.yml << 'eof'
version: '3.6'
services:
gitlab:
image: gitlab/gitlab-ce:latest
container_name: gitlab
restart: always
hostname: 'gitlab.example.com' # 修改为您的域名或ip
environment:
gitlab_omnibus_config: |
external_url 'http://192.168.1.100' # 修改为您的ip或域名
gitlab_rails['gitlab_shell_ssh_port'] = 2222
gitlab_rails['smtp_enable'] = false
gitlab_rails['time_zone'] = 'asia/shanghai'
ports:
- "80:80"
- "443:443"
- "2222:22"
volumes:
- /srv/gitlab/config:/etc/gitlab
- /srv/gitlab/logs:/var/log/gitlab
- /srv/gitlab/data:/var/opt/gitlab
networks:
- gitlab-network
shm_size: '256m'
networks:
gitlab-network:
driver: bridge
eof
# 启动gitlab
docker-compose -f docker-compose-gitlab.yml up -d2. 配置gitlab
# 获取初始root密码 sudo docker exec -it gitlab cat /etc/gitlab/initial_root_password # 登录gitlab (http://your-server-ip) # 用户名: root # 密码: 从上述命令获取
第二部分:jenkins安装与配置
1. 使用docker安装jenkins
# 创建jenkins数据目录
sudo mkdir -p /srv/jenkins_home
# 设置目录权限
sudo chown -r 1000:1000 /srv/jenkins_home
# 创建docker-compose.yml
cat > docker-compose-jenkins.yml << 'eof'
version: '3.7'
services:
jenkins:
image: jenkins/jenkins:lts-jdk17
container_name: jenkins
restart: always
user: "1000:1000" # 使用非root用户
ports:
- "8080:8080"
- "50000:50000"
volumes:
- /srv/jenkins_home:/var/jenkins_home
- /var/run/docker.sock:/var/run/docker.sock
- /usr/bin/docker:/usr/bin/docker
environment:
- java_opts=-djenkins.install.runsetupwizard=false
networks:
- jenkins-network
networks:
jenkins-network:
driver: bridge
eof
# 启动jenkins
docker-compose -f docker-compose-jenkins.yml up -d
# 查看初始管理员密码
sudo cat /srv/jenkins_home/secrets/initialadminpassword第三部分:案例实战 - spring boot应用ci/cd
1. 准备示例项目
# 在gitlab创建新项目
# 项目名称: spring-boot-demo
# 可见性: private
# 本地准备spring boot项目
mkdir spring-boot-demo && cd spring-boot-demo
# 创建项目结构
cat > pom.xml << 'eof'
<?xml version="1.0" encoding="utf-8"?>
<project xmlns="http://maven.apache.org/pom/4.0.0"
xmlns:xsi="http://www.w3.org/2001/xmlschema-instance"
xsi:schemalocation="http://maven.apache.org/pom/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelversion>4.0.0</modelversion>
<groupid>com.example</groupid>
<artifactid>spring-boot-demo</artifactid>
<version>1.0.0</version>
<packaging>jar</packaging>
<parent>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-starter-parent</artifactid>
<version>2.7.0</version>
<relativepath/>
</parent>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-starter-web</artifactid>
</dependency>
<dependency>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-starter-test</artifactid>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-maven-plugin</artifactid>
</plugin>
</plugins>
</build>
</project>
eof
# 创建java源码
mkdir -p src/main/java/com/example/demo
cat > src/main/java/com/example/demo/demoapplication.java << 'eof'
package com.example.demo;
import org.springframework.boot.springapplication;
import org.springframework.boot.autoconfigure.springbootapplication;
import org.springframework.web.bind.annotation.getmapping;
import org.springframework.web.bind.annotation.restcontroller;
@springbootapplication
@restcontroller
public class demoapplication {
@getmapping("/")
public string hello() {
return "hello from spring boot ci/cd pipeline!";
}
@getmapping("/health")
public string health() {
return "status: up";
}
public static void main(string[] args) {
springapplication.run(demoapplication.class, args);
}
}
eof
# 创建测试文件
mkdir -p src/test/java/com/example/demo
cat > src/test/java/com/example/demo/demoapplicationtest.java << 'eof'
package com.example.demo;
import org.junit.jupiter.api.test;
import org.springframework.beans.factory.annotation.autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.autoconfiguremockmvc;
import org.springframework.boot.test.context.springboottest;
import org.springframework.test.web.servlet.mockmvc;
import org.springframework.test.web.servlet.request.mockmvcrequestbuilders;
import static org.springframework.test.web.servlet.result.mockmvcresultmatchers.status;
import static org.springframework.test.web.servlet.result.mockmvcresultmatchers.content;
@springboottest
@autoconfiguremockmvc
class demoapplicationtest {
@autowired
private mockmvc mockmvc;
@test
void testhelloendpoint() throws exception {
mockmvc.perform(mockmvcrequestbuilders.get("/"))
.andexpect(status().isok())
.andexpect(content().string("hello from spring boot ci/cd pipeline!"));
}
@test
void testhealthendpoint() throws exception {
mockmvc.perform(mockmvcrequestbuilders.get("/health"))
.andexpect(status().isok())
.andexpect(content().string("status: up"));
}
}
eof
# 创建dockerfile
cat > dockerfile << 'eof'
from openjdk:17-jdk-slim as builder
workdir /app
copy . .
run ./mvnw clean package -dskiptests
from openjdk:17-jre-slim
workdir /app
copy --from=builder /app/target/*.jar app.jar
expose 8080
entrypoint ["java", "-jar", "app.jar"]
eof
# 创建部署脚本
cat > deploy.sh << 'eof'
#!/bin/bash
# 部署脚本
set -e
app_name="spring-boot-demo"
container_name="spring-boot-app"
version=${build_number:-latest}
echo "开始部署版本: $version"
# 停止并删除旧容器
docker stop $container_name || true
docker rm $container_name || true
# 运行新容器
docker run -d \
--name $container_name \
--restart always \
-p 8081:8080 \
-e spring_profiles_active=prod \
$app_name:$version
echo "部署完成!"
docker ps | grep $container_name
eof
chmod +x deploy.sh
# 创建.gitlab-ci.yml
cat > .gitlab-ci.yml << 'eof'
stages:
- build
- test
- package
- deploy
variables:
maven_opts: "-dmaven.repo.local=.m2/repository"
cache:
paths:
- .m2/repository/
- target/
build:
stage: build
image: maven:3.8.6-openjdk-17
script:
- mvn clean compile
artifacts:
paths:
- target/
test:
stage: test
image: maven:3.8.6-openjdk-17
script:
- mvn test
coverage: '/total.*?([0-9]{1,3})%/'
package:
stage: package
image: maven:3.8.6-openjdk-17
script:
- mvn package -dskiptests
artifacts:
paths:
- target/*.jar
deploy:
stage: deploy
image: docker:latest
services:
- docker:dind
variables:
docker_host: tcp://docker:2375
docker_driver: overlay2
script:
- docker build -t spring-boot-demo:$ci_commit_short_sha .
- docker tag spring-boot-demo:$ci_commit_short_sha spring-boot-demo:latest
- docker run -d -p 8081:8080 --name spring-boot-app spring-boot-demo:latest
only:
- main
environment:
name: production
url: http://your-server-ip:8081
eof2. jenkins配置
安装必要插件
访问 jenkins: http://your-server-ip:8080
安装插件:
- gitlab plugin
- pipeline
- maven integration
- docker pipeline
- blue ocean
创建pipeline任务
新建item → 选择 pipeline
配置:
- pipeline: pipeline script from scm
- scm: git
- repository url: http://gitlab-server/root/spring-boot-demo.git
- credentials: 添加gitlab凭据
- branch specifier: */main
- script path: jenkinsfile
创建jenkinsfile (在项目根目录)
groovy
pipeline {
agent any
tools {
maven 'maven-3.8'
jdk 'jdk-17'
}
stages {
stage('checkout') {
steps {
git branch: 'main',
url: 'http://gitlab-server/root/spring-boot-demo.git',
credentialsid: 'gitlab-credentials'
}
}
stage('build') {
steps {
sh 'mvn clean compile'
}
}
stage('unit test') {
steps {
sh 'mvn test'
}
post {
always {
junit 'target/surefire-reports/*.xml'
}
}
}
stage('code analysis') {
steps {
sh 'mvn checkstyle:checkstyle pmd:pmd'
}
}
stage('package') {
steps {
sh 'mvn package -dskiptests'
}
post {
success {
archiveartifacts 'target/*.jar'
}
}
}
stage('build docker image') {
steps {
script {
docker.build("spring-boot-demo:${env.build_id}")
}
}
}
stage('deploy to test') {
steps {
sh '''
docker stop spring-boot-test || true
docker rm spring-boot-test || true
docker run -d --name spring-boot-test -p 8082:8080 spring-boot-demo:${build_id}
'''
}
}
stage('integration test') {
steps {
sh '''
sleep 10 # 等待应用启动
curl -f http://localhost:8082/health || exit 1
'''
}
}
stage('deploy to production') {
when {
branch 'main'
}
steps {
sh '''
docker tag spring-boot-demo:${build_id} spring-boot-demo:latest
docker stop spring-boot-prod || true
docker rm spring-boot-prod || true
docker run -d --name spring-boot-prod -p 8081:8080 --restart always spring-boot-demo:latest
'''
}
}
}
post {
success {
emailext (
subject: "构建成功: ${env.job_name} - ${env.build_number}",
body: "项目构建成功,请访问: http://your-server-ip:8081",
to: 'admin@example.com'
)
}
failure {
emailext (
subject: "构建失败: ${env.job_name} - ${env.build_number}",
body: "项目构建失败,请检查日志",
to: 'admin@example.com'
)
}
}
}3. gitlab webhook配置
在gitlab项目中:
- settings → webhooks
- url: http://jenkins-server:8080/project/spring-boot-demo
- secret token: (生成并复制)
在jenkins中:
- 项目配置 → build triggers
- 勾选 "build when a change is pushed to gitlab"
- 添加secret token (与gitlab中相同)
第四部分:ci/cd流程测试
1. 推送代码触发构建
# 初始化git仓库 git init git add . git commit -m "initial commit" git remote add origin http://gitlab-server/root/spring-boot-demo.git git push -u origin main
2. 监控流程
# 查看jenkins构建日志 docker logs -f jenkins # 查看应用运行状态 docker ps # 测试应用 curl http://localhost:8081 curl http://localhost:8081/health
第五部分:高级配置
1. 配置slack通知
# jenkins安装slack notification插件
# jenkinsfile中添加
post {
success {
slacksend(
color: 'good',
message: "构建成功: ${env.job_name} - ${env.build_number}"
)
}
failure {
slacksend(
color: 'danger',
message: "构建失败: ${env.job_name} - ${env.build_number}"
)
}
}2. 配置sonarqube代码质量检查
groovy
stage('sonarqube analysis') {
steps {
withsonarqubeenv('sonarqube-server') {
sh 'mvn sonar:sonar'
}
}
}3. 使用kubernetes部署
yaml
# 创建k8s部署文件 deployment.yaml
apiversion: apps/v1
kind: deployment
metadata:
name: spring-boot-app
spec:
replicas: 3
selector:
matchlabels:
app: spring-boot-app
template:
metadata:
labels:
app: spring-boot-app
spec:
containers:
- name: spring-boot-app
image: spring-boot-demo:latest
ports:
- containerport: 8080故障排除
常见问题解决
# 1. jenkins无法连接gitlab
# 检查网络连通性
docker network ls
docker network connect gitlab-network jenkins
# 2. maven构建缓慢
# 配置阿里云镜像
mkdir -p ~/.m2
cat > ~/.m2/settings.xml << 'eof'
<settings>
<mirrors>
<mirror>
<id>aliyun</id>
<name>aliyun maven mirror</name>
<url>https://maven.aliyun.com/repository/public</url>
<mirrorof>central</mirrorof>
</mirror>
</mirrors>
</settings>
eof
# 3. docker权限问题
sudo chmod 666 /var/run/docker.sock
# 4. 查看日志
docker logs gitlab
docker logs jenkins
journalctl -u docker --follow这个完整的ci/cd案例包含了从环境搭建到自动化部署的全过程,可以根据实际需求进行调整和扩展。
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。
发表评论