Jenkins最新版 Linux/Docker部署(两种方案)

0 阅读3分钟

前言

版本介绍:

  • Jenkins :2.504.1 LTS
  • JDK:使用JDK21运行jenkins,JDK8跑程序应用
  • maven:3.9.9

该文档分为两种模式进行部署

  • 使用原始的Linux(Centos)本机上部署Jenkins
  • 使用Docker中的docker-compoe部署Jenkins

Linux 部署

文件准备

jenkins.zip

解压命令

tar -zxvf apache-maven-3.9.9-bin.tar.gz
tar -zxvf openjdk-21.0.1_linux-x64_bin.tar.gz
mv settings.xml ./apache-maven-3.9.9/conf

设置maven环境变量(如果已装请跳过)

# 编辑配置文件
vim /etc/profile

# 在末尾追加
export MAVEN_HOME=/usr/local/jenkins/apache-maven-3.9.9/
export PATH=${PATH}:${MAVEN_HOME}/bin

# 使配置文件生效
source /etc/profile

# 测试
mvn -v

安装git(如果已装请跳过)

yum -y install git-core

启动jenkins

sh run_jenkins.sh

Docker 安装

文件准备

jenkins.zip

Docker-compose

Dockerfile

# 第一阶段:构建工具镜像
FROM eclipse-temurin:21-jdk as builder
USER root

# 创建工作目录并设置权限
RUN mkdir -p /var/jenkins_home && chmod -R 777 /var/jenkins_home

# 安装JDK8
COPY OpenJDK8U-jdk.tar.gz /tmp/
RUN mkdir -p /usr/lib/jvm && \
    tar -xzf /tmp/OpenJDK8U-jdk.tar.gz -C /usr/lib/jvm/ && \
    rm /tmp/OpenJDK8U-jdk.tar.gz && \
    update-alternatives --install /usr/bin/java java /usr/lib/jvm/jdk8u392-b08/bin/java 1000 && \
    update-alternatives --set java /usr/lib/jvm/jdk8u392-b08/bin/java

# 安装Maven
COPY apache-maven-3.6.3-bin.tar.gz /tmp/
COPY settings.xml /tmp/
RUN tar -xzf /tmp/apache-maven-3.6.3-bin.tar.gz -C /usr/share/ && \
    mv /usr/share/apache-maven-3.6.3 /usr/share/maven && \
    mkdir -p /usr/share/maven/conf && \
    cp /tmp/settings.xml /usr/share/maven/conf/ && \
    rm -rf /tmp/*

# 第二阶段:运行时镜像
FROM eclipse-temurin:21-jdk
USER root

# 复制构建产物
COPY --from=builder /usr/lib/jvm/jdk8u392-b08 /usr/lib/jvm/jdk8
COPY --from=builder /usr/share/maven /usr/share/maven
COPY jenkins.war /opt/jenkins.war

# 安装系统依赖
RUN apt-get update && \
    apt-get install -y git curl && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

# 配置环境变量
ENV JAVA_HOME=/usr/lib/jvm/jdk8 \
    JAVA21_HOME=/opt/java/openjdk \
    MAVEN_HOME=/usr/share/maven \
    JENKINS_HOME=/var/jenkins_home \
    PATH="/usr/share/maven/bin:/usr/lib/jvm/jdk8/bin:/opt/java/openjdk/bin:$PATH"

# 初始化目录结构(关键修复)
RUN mkdir -p /var/jenkins_home/war/META-INF && \
    chown -R root:root /var/jenkins_home && \
    chmod -R 755 /var/jenkins_home

# 容器配置
EXPOSE 8080 50000
HEALTHCHECK --interval=30s --timeout=5s \
  CMD curl -fsS http://localhost:8080/login > /dev/null || exit 1

# 关键修复:使用绝对路径替代环境变量引用
CMD ["/opt/java/openjdk/bin/java", "-Djava.awt.headless=true", "-jar", "/opt/jenkins.war", "--httpPort=8080", "--webroot=/var/jenkins_home/war"]

docker-compose.yml

version: '3.8'

services:
  jenkins:
    build: 
      context: .
      dockerfile: Dockerfile
    container_name: jenkins
    restart: unless-stopped
    ports:
      - "8080:8080"
      - "50000:50000"
    volumes:
      - ./jenkins_home:/var/jenkins_home
      - ./m2_repo:/home/jenkins/.m2
      - /var/run/docker.sock:/var/run/docker.sock
      # 挂载自定义settings.xml(可覆盖默认配置)
      - ./settings.xml:/usr/share/maven/ref/settings.xml
    environment:
      - TZ=Asia/Shanghai
      - MAVEN_CONFIG=/home/jenkins/.m2  # Maven配置路径
      - JAVA_OPTS=-Djenkins.install.runSetupWizard=false
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/login"]
      interval: 30s
      timeout: 5s
      retries: 3

volumes:
  jenkins_home:
  m2_repo:

启动jenkins

docker compose up -d

插件

中文插件

Locale

内置SSH服务器

Publish Over SSH

资源监控

Monitoring

界面美化

Blue Ocean

代码管理

Git、Maven Integration、SCM-Manager

离线安装

plugins.jenkins.io/ui/search/?…

系统配置

配置邮箱

  1. 系统管理员地址:用户名@163.com
  2. 邮件通知:
    1. SMTP服务器:smtp.163.com
    2. SMTP认证
      1. 用户名:用户名@163.com
      2. 密码:XXXXXXXX
    1. SMTP端口:25
    2. 回复地址:用户名@163.com
    3. 字符集:UTF-8
    4. 测试发件邮箱:用户名@qq.com

SSH Server

添加服务器

Name:10.0.110.167
Hostname:10.0.110.167
Username:root
Remote Directory:/
Password:XXXXXXXX

全局配置

Maven 配置

默认 settings 提供

/usr/share/maven/conf/settings.xml

MAVEN_HOME

/usr/share/maven

Git配置

Name

Default

Path to Git executable

/usr/bin/git

JDK配置

Name

JDK1.8

JAVA_HOME

/usr/lib/jvm/jdk8

设置全局凭证

Gitee账号

用户名:bdmcom
私人令牌:XXXXXXX

新建任务(基于MAVEN)

  1. 选择Maven项目
  2. 源码管理
    1. 仓库地址:gitee.com/bdmcom/spri…
    2. 添加Giee凭证
    3. 选择分支:*/master
  1. 触发器
    1. 选择轮询SCM:*/1 * * * *
  1. 环境
    1. 在构建开始之前,通过SSH发生文件或者执行命令
      1. 选择目标服务器
      2. 设置远程目录:/usr/local/services/04system/temp
      3. 执行命令:
      4. cd /usr/local/services/04system/temp/logs
      5. echo "[(date+(date +'%Y-%m-%d %T')] user:(whoami), host:(hostname),script:(hostname), script:(basename $0), pid:$$] - 构建开始" >> jenkins.log
    1. 在构建开始之后,通过SSH发生文件或者执行命令
      1. 选择目标服务器
      2. 设置远程目录:/usr/local/services/04system/temp
      3. 执行命令:
      4. cd /usr/local/services/04system/temp/logs
      5. echo "[(date+(date +'%Y-%m-%d %T')] user:(whoami), host:(hostname),script:(hostname), script:(basename $0), pid:$$] - 构建结束" >> jenkins.log
  1. 构建
    1. 根POM:pom.xml
    2. 目标和选择:clean install -Dmaven.test.skip=true
    3. 高级
      1. MAVEN_OPTS:-Dmaven.test.skip=true
      2. 配置文件路径:/usr/share/maven/conf/settings.xml
  1. 构建成功后运行
    1. 选择目标服务器
    2. 源文件:**/*.jar
    3. 删除前缀:/target
    4. 执行命令:
    5. cd /usr/local/services/04system/temp
    6. sh start_application.sh restart
    7. cd /usr/local/services/04system/temp/logs
    8. echo "[(date+(date +'%Y-%m-%d %T')] user:(whoami), host:(hostname),script:(hostname), script:(basename $0), pid:$$] - 构建中" >> jenkins.log
    9. cd /usr/local/services/04system/temp
    10. sh build_docker.sh
    11. docker compose up -d

脚本(参考)

启动 java jar 包脚本

config.sh

# config.sh

# JDK所在路径
JAVA_HOME="/usr/local/java"

# jar所在的路径
APP_PATH="/usr/local/services/04system/"

# 加载静态参数
APP_MAINCLASS="dcim-system.jar"

# Java虚拟机启动参数
JAVA_OPTS="-Xms128m -Xmx512m"

# 日志文件路径
LOG_FILE="${APP_PATH}/logs/start_application.log"

start_application.sh

#!/bin/sh
#该脚本为Linux下启动java程序的通用脚本。即可以作为开机自启动service脚本被调用,
#也可以作为启动java程序的独立脚本来使用。
#
#Author: yangpeng
#
#Warning:该脚本stop部分使用系统kill命令来强制终止指定的java程序进程。
#在杀死进程前,未作任何条件检查。在某些情况下,如程序正在进行文件或数据库写操作,
#可能会造成数据丢失或数据不完整。如果必须要考虑到这类情况,则需要改写此脚本,
#增加在执行kill命令前的一系列检查。
#
###################################
#加载配置文件
CONFIG_FILE="./config.sh"

if [ ! -f "$CONFIG_FILE" ]; then
    echo "Configuration file not found: $CONFIG_FILE"
    exit 1
fi

# 加载配置文件
. "$CONFIG_FILE"

log() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') - $*" >> "$LOG_FILE"
}

print_status() {
    local message="$1"
    local status="$2"
    echo "$message"
    log "$message"
    if [ "$status" -eq 0 ]; then
        echo "[OK]"
    else
        echo "[Failed]"
    fi
}

###################################
#(函数)判断程序是否已启动
#
#说明:
#使用JDK自带的JPS命令及grep命令组合,准确查找pid
#jps 加 l 参数,表示显示java的完整包路径
#使用awk,分割出pid ($1部分),及Java程序名称($2部分)
###################################
#初始化psid变量(全局)
psid=0

checkpid() {
   javaps="$($JAVA_HOME/bin/jps -l | grep "$APP_MAINCLASS")"

   if [ -n "$javaps" ]; then
      psid=$(echo "$javaps" | awk '{print $1}')
   else
      psid=0
   fi
}

###################################
#(函数)启动程序
#
#说明:
#1. 首先调用checkpid函数,刷新$psid全局变量
#2. 如果程序已经启动($psid不等于0),则提示程序已启动
#3. 如果程序没有被启动,则执行启动命令行
#4. 启动命令执行后,再次调用checkpid函数
#5. 如果步骤4的结果能够确认程序的pid,则打印[OK],否则打印[Failed]
#注意:echo -n 表示打印字符后,不换行
#注意: "nohup 某命令 >/dev/null 2>&1 &" 的用法
###################################
start() {
   checkpid

   if [ $psid -ne 0 ]; then
      print_status "warn: $APP_MAINCLASS already started! (pid=$psid)" 0
   else
      log "Starting $APP_MAINCLASS ..."
      nohup $JAVA_HOME/bin/java -Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=9057 -jar $JAVA_OPTS "$APP_PATH/$APP_MAINCLASS" >/dev/null 2>&1 &
      checkpid
      if [ $psid -ne 0 ]; then
         print_status "Started successfully (pid=$psid)" 0
      else
         print_status "Failed to start" 1
      fi
   fi
}

###################################
#(函数)停止程序
#
#说明:
#1. 首先调用checkpid函数,刷新$psid全局变量
#2. 如果程序已经启动($psid不等于0),则开始执行停止,否则,提示程序未运行
#3. 使用kill -9 pid命令进行强制杀死进程
#4. 执行kill命令行紧接其后,马上查看上一句命令的返回值: $?
#5. 如果步骤4的结果$?等于0,则打印[OK],否则打印[Failed]
#6. 为了防止java程序被启动多次,这里增加反复检查进程,反复杀死的处理(递归调用stop)。
#注意:echo -n 表示打印字符后,不换行
#注意: 在shell编程中,"$?" 表示上一句命令或者一个函数的返回值
###################################
stop() {
   checkpid

   if [ $psid -ne 0 ]; then
      log "Stopping $APP_MAINCLASS ...(pid=$psid)"
      kill -9 $psid
      local kill_status=$?
      if [ $kill_status -eq 0 ]; then
         print_status "Stopped successfully" 0
      else
         print_status "Failed to stop" 1
      fi

      checkpid
      if [ $psid -ne 0 ]; then
         stop
      fi
   else
      print_status "warn: $APP_MAINCLASS is not running" 0
   fi
}

###################################
#读取脚本的第一个参数($1),进行判断
#参数取值范围:{start|stop|restart|status|info}
#如参数不在指定范围之内,则打印帮助信息
###################################
case "$1" in
    start)
        start
        ;;
    stop)
        stop
        ;;
    restart)
        stop
        start
        ;;
    status)
        checkpid
        if [ $psid -ne 0 ]; then
            print_status "$APP_MAINCLASS is running (pid=$psid)" 0
        else
            print_status "$APP_MAINCLASS is not running" 0
        fi
        ;;
    info)
        echo "JAVA_HOME: $JAVA_HOME"
        echo "APP_PATH: $APP_PATH"
        echo "APP_MAINCLASS: $APP_MAINCLASS"
        echo "JAVA_OPTS: $JAVA_OPTS"
        ;;
    *)
        echo "Usage: $0 {start|stop|restart|status|info}"
        exit 1
        ;;
esac

exit 0

Dockerfile

# 使用OpenJDK 8的Alpine JRE镜像(仅运行环境,体积更小)
FROM openjdk:8-jre-alpine

# 合并时区设置与清理命令,减少层数[1,2](@ref)
RUN apk add --no-cache tzdata \
    && ln -snf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
    && echo "Asia/Shanghai" > /etc/timezone \
    && rm -rf /var/cache/apk/*

# 设置工作目录和统一环境变量
WORKDIR /app
ENV SERVER_PORT=4430 JAVA_OPTS=""

# 分阶段复制文件以利用缓存[1,5](@ref)
COPY application.yml ./config/
COPY dcim-system.jar ./

# 统一暴露端口与应用端口[7,8](@ref)
EXPOSE ${SERVER_PORT}

# 启动命令显式指定端口(覆盖配置)
ENTRYPOINT exec java ${JAVA_OPTS} -Dserver.port=${SERVER_PORT} -jar dcim-system.jar

构建镜像

#!/bin/sh
docker compose down

docker rmi dcim-system:1.0.0

docker build  -t dcim-system:1.0.0 .

docker-compose.yml

version: '3.8'
services:
  dcim-system:
    image: dcim-system:1.0.0
    container_name: dcim-system
    restart: unless-stopped
    ports:
      - "4430:4430"
    volumes:
      - ./logs:/app/logs  # 保留 SELinux 标签配置
    environment:
      - JAVA_OPTS=-Xms256m -Xmx1536m
    networks:
      - backend_network
    healthcheck:  # 健康检查机制保留
      test: ["CMD", "curl", "-f", "http://localhost:4430/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s
    logging:  # 日志管理策略保留
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"

networks:
  backend_network:  # 网络隔离配置保留
    driver: bridge
    attachable: true

镜像上传到Harbor

#!/bin/bash
# 设置Harbor仓库配置(根据实际环境修改)
HARBOR_URL="10.0.110.XXX:8858"      # Harbor服务器地址
HARBOR_USER="root"                  # 用户名
HARBOR_PASS="XXXXXXX"            # 密码
HARBOR_PROJECT="dcim"           # 目标项目名称

# 设置镜像配置
IMAGE_NAME="dcim-system"                   # 镜像名称(与Dockerfile对应)
TAG_NAME=$(date +%Y%m%d%H%M%S)       # 自动生成时间戳标签(避免使用latest)

# 步骤1:构建Docker镜像
echo "正在构建镜像 ${IMAGE_NAME}:${TAG_NAME}..."
docker build -t ${IMAGE_NAME}:${TAG_NAME} . 

# 检查构建结果
if [ $? -ne 0 ]; then
    echo "[错误] 镜像构建失败,请检查Dockerfile"
    exit 1
fi

# 步骤2:登录Harbor仓库
echo "登录Harbor仓库 ${HARBOR_URL}..."
docker login ${HARBOR_URL} -u ${HARBOR_USER} -p ${HARBOR_PASS}

if [ $? -ne 0 ]; then
    echo "[错误] Harbor登录失败,请检查:"
    echo "- 网络连通性"
    echo "- /etc/docker/daemon.json是否配置insecure-registries[8](@ref)"
    exit 1
fi

# 步骤3:标记镜像(符合Harbor命名规范[7,11](@ref))
HARBOR_IMAGE="${HARBOR_URL}/${HARBOR_PROJECT}/${IMAGE_NAME}:${TAG_NAME}"
docker tag ${IMAGE_NAME}:${TAG_NAME} ${HARBOR_IMAGE}

# 步骤4:推送镜像
echo "正在推送 ${HARBOR_IMAGE}..."
docker push ${HARBOR_IMAGE}

if [ $? -eq 0 ]; then
    echo "推送成功!"
    echo "镜像地址:${HARBOR_IMAGE}"
    
    # 清理临时标签
    docker rmi ${HARBOR_IMAGE} 2>/dev/null
    echo "已清理临时标签"
else
    echo "[错误] 推送失败,可能原因:"
    echo "- 项目${HARBOR_PROJECT}不存在[2](@ref)"
    echo "- 用户无项目权限"
    exit 1
fi