构建前后端镜像由于jenkins服务是使用jenkins普通用户运行的所以在调用docker命令的时候是没有权限的所以需要提前将jenkins用户加入到docker的组里面.在 Jenkins 所在的服务器上执行以下命令把 jenkins 用户加入docker组# sudo usermod -aG docker jenkins刷新用户组# newgrp docker验证重启 Jenkins 后在 Jenkins 服务器上用 jenkins 用户身份测试运行# su - jenkins# docker ps如果能正常输出容器列表说明权限已经生效。部署harbor镜像仓库172.20.10.3 安装docker和docker-compose 安装docker略 [rootlocalhost ~]# curl -SL https://github.com/docker/compose/releases/download/v2.24.6/docker-compose-linux-x86_64 -o /usr/local/bin/docker-compose [rootlocalhost ~]# chmod x /usr/local/bin/docker-compose [rootlocalhost ~]# docker-compose -v Docker Compose version v2.24.6 [rootlocalhost ~]# wget https://github.com/goharbor/harbor/releases/download/v2.15.0/harbor-offline-installer-v2.15.0.tgz [rootlocalhost ~]# tar xf harbor-offline-installer-v2.15.0.tar [rootlocalhost ~]# cd harbor [rootlocalhost harbor]# ls common.sh harbor.v2.15.0.tar.gz harbor.yml.tmpl install.sh LICENSE prepare [rootlocalhost harbor]# cp harbor.yml.tmpl harbor.yml #生成证书生产环境中可购买证书使用 #生成 CA 根证书自签 [rootlocalhost harbor]# mkdir -p /data/harbor/certs [rootlocalhost harbor]# cd /data/harbor/certs [rootlocalhost certs]# openssl genrsa -out ca.key 4096 Generating RSA private key, 4096 bit long modulus .. ...................... e is 65537 (0x10001) [rootlocalhost certs]# openssl req -x509 -new -nodes -sha512 -days 3650 -subj /CCN/STBeijing/LBeijing/OHarbor/OUIT/CN172.20.10.3 -key ca.key -out ca.crt #生成服务器证书IP [rootlocalhost certs]# openssl genrsa -out harbor.key 4096 Generating RSA private key, 4096 bit long modulus .......... ........................................................................................................................................................................................................................ e is 65537 (0x10001) [rootlocalhost certs]# openssl req -sha512 -new -subj /CCN/STBeijing/LBeijing/OHarbor/OUIT/CN172.20.10.3 -key harbor.key -out harbor.csr [rootlocalhost certs]# cat v3.ext -EOF authorityKeyIdentifierkeyid,issuer basicConstraintsCA:FALSE keyUsage digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment extendedKeyUsage serverAuth subjectAltName IP:172.20.10.3 EOF [rootlocalhost certs]# openssl x509 -req -sha512 -days 3650 \ -extfile v3.ext \ -CA ca.crt -CAkey ca.key -CAcreateserial \ -in harbor.csr \ -out harbor.crt Signature ok subject/CCN/STBeijing/LBeijing/OHarbor/OUIT/CN172.20.10.3 Getting CA Private Key [rootlocalhost certs]# ls ca.crt ca.key ca.srl harbor.crt harbor.csr harbor.key v3.ext [rootlocalhost harbor]# vim harbor.yml[rootlocalhost harbor]# ./install.sh[rootlocalhost harbor]# docker-compose up -d[rootlocalhost harbor]# netstat -lntp | egrep :80 | :443tcp000.0.0.0:800.0.0.0:* LISTEN75137/docker-proxy tcp600:::80 :::* LISTEN75141/docker-proxy客户端配置Docker 信任自签证书服务端Harbor 本机[rootlocalhost ~]# mkdir -p /etc/docker/certs.d/172.20.10.3 [rootlocalhost ~]# cp /data/harbor/certs/ca.crt /etc/docker/certs.d/172.20.10.3/ [rootlocalhost ~]# ls /etc/docker/certs.d/172.20.10.3/ ca.crt [rootlocalhost ~]# systemctl restart docker2.其他 Docker 客户端[rootjenkins-slave ~]# mkdir -p /etc/docker/certs.d/172.20.10.3[rootjenkins-slave ~]# scp root172.20.10.3:/data/harbor/certs/ca.crt /etc/docker/certs.d/172.20.10.3[rootjenkins-slave ~]# systemctl restart docker#测试[rootjenkins-slave ~]# docker login https://172.20.10.3Username: admin Password: WARNING!Your password will be stored unencryptedin/root/.docker/config.json. Configure a credential helper to remove this warning. See https://docs.docker.com/engine/reference/commandline/login/#credentials-storeLogin Succeeded在jenkins的主从节点配置以不安全的方式访问harbor仓库[rootjenkins ~]# cat /etc/docker/daemon.json{registry-mirrors:[https://08c765900e00f5d20f0dc0005a40c3a0.mirror.swr.myhuaweicloud.com],insecure-registries:[172.20.10.3]}[rootjenkins ~]# systemctl daemon-reload[rootjenkins ~]# systemctl restart docker[rootjenkins-slave ~]# cat /etc/docker/daemon.json{registry-mirrors:[https://08c765900e00f5d20f0dc0005a40c3a0.mirror.swr.myhuaweicloud.com],insecure-registries:[172.20.10.3]}[rootjenkins-slave ~]# systemctl daemon-reload[rootjenkins-slave ~]# systemctl restart docker在harbor仓库创建对应的项目仓库在jenkins上面创建登录harbor仓库的凭据选择用户名和密码类型的凭据新建任务编写流水线pipeline { agent none options { timestamps() timeout(time: 1, unit: HOURS) buildDiscarder(logRotator(numToKeepStr: 10)) } environment { // GIT 配置 FRONTEND_GIT_URL gitgitee.com:testpm/frontend-demo.git BACKEND_GIT_URL gitgitee.com:testpm/backend-demo.git SLAVE_GIT_ID jenkins-slave-git // 镜像仓库配置 REGISTRY 172.20.10.3 BACK_NAMESPACE backend BACK_APP_NAME my-backend FRONT_NAMESPACE frontend FRONT_APP_NAME my-frontend // 镜像仓库凭证 DOCKER_CRED credentials(harbor-secret) } stages { // // 一、构建后端服务 // stage( 构建后端镜像) { agent { node { label jenkins-slave customWorkspace /home/jenkins/backend-docker } } steps { echo 拉取后端代码 git credentialsId: ${SLAVE_GIT_ID}, url: ${BACKEND_GIT_URL}, branch: master echo 计算镜像版本号 // 关键修复在 git 命令执行后立即在当前目录计算 COMMIT_HASH script { // 这里会在 /home/jenkins/backend-docker 目录下执行因为有 git 拉取所以一定有 .git env.COMMIT_HASH sh(returnStdout: true, script: git rev-parse --short HEAD).trim() env.BACK_FULL_IMAGE ${REGISTRY}/${BACK_NAMESPACE}/${BACK_APP_NAME}:${COMMIT_HASH} } echo 镜像地址${BACK_FULL_IMAGE} sh pwd ls -la | grep .git // 验证目录和git存在 echo 构建并推送后端镜像 sh set -eux echo ${DOCKER_CRED_PSW} | docker login -u ${DOCKER_CRED_USR} --password-stdin ${REGISTRY} docker build -t $BACK_FULL_IMAGE . docker push $BACK_FULL_IMAGE docker logout $REGISTRY } } // // 二、构建前端服务 // stage( 构建前端镜像) { agent { node { label jenkins-slave customWorkspace /home/jenkins/frontend-docker } } steps { echo 拉取前端代码 git credentialsId: ${SLAVE_GIT_ID}, url: ${FRONTEND_GIT_URL}, branch: master echo 计算镜像版本号 script { // 前端目录计算版本号 env.COMMIT_HASH sh(returnStdout: true, script: git rev-parse --short HEAD).trim() env.FRONT_FULL_IMAGE ${REGISTRY}/${FRONT_NAMESPACE}/${FRONT_APP_NAME}:${COMMIT_HASH} } echo 镜像地址${FRONT_FULL_IMAGE} sh pwd ls -la | grep .git echo 构建并推送前端镜像 sh set -eux docker login -u $DOCKER_CRED_USR -p $DOCKER_CRED_PSW $REGISTRY docker build -t $FRONT_FULL_IMAGE . docker push $FRONT_FULL_IMAGE docker logout $REGISTRY } } } }前后端的dockerfile[rootjenkins-slave ~]# cat backend-demo/Dockerfile# 第一阶段构建FROM maven:3.9.9-eclipse-temurin-21 AS build WORKDIR /app COPY pom.xml.RUN mvn dependency:go-offline-BCOPY src ./src RUN mvn clean package-DskipTests# 第二阶段运行FROM openjdk:21-jre-slim WORKDIR /app COPY--frombuild /app/target/*.jar app.jar EXPOSE8080ENTRYPOINT[java,-jar,app.jar][rootjenkins-slave ~]# cat frontend-demo/Dockerfile# 构建阶段FROM node:16 as build-stage RUNnpmconfigsetregistry https://registry.npmmirror.com WORKDIR /app COPY package*.json ./ RUNnpminstallCOPY..RUNnpmrun build:prod# 生产阶段FROM nginx:alpine WORKDIR /usr/share/nginx/html COPY--frombuild-stage /app/dist.COPY nginx.conf /etc/nginx/nginx.conf EXPOSE80CMD[nginx,-g,daemon off;]主要问题1.sh命令必须在node块 里运行因为只有node块才会分配一个执行节点和对应的工作目录。 为什么会这样Jenkins Pipeline 里所有需要操作文件系统、执行 Shell 命令的步骤sh/bat/git等都必须运行在node块中。node块会帮你分配一个执行节点、创建工作目录、初始化FilePath上下文。没有node块sh命令就像 “飘在空气里”不知道要在哪台机器、哪个目录下运行就会报错。第二个问题执行的命令是git rev-parse --short HEAD用来获取当前commit的短哈希。报错说明 Jenkins 当前所在的目录里没有找到 .git 子目录即这个目录不是 Git 仓库。结合日志看后端阶段Runningin/home/jenkins/backend-docker 错误发生时Runningin/home/jenkins/workspace/pm-docker这说明工作目录被意外切换了导致你的COMMIT_HASH变量在错误的目录下执行。️ 根本原因与修复方案你使用了customWorkspace自定义工作目录这会改变节点的工作路径。但在 Groovy 中直接在顶层environment里执行sh命令不会自动进入你配置的customWorkspace它会走默认的工作目录workspace/pm-docker从而找不到 .git。修复方法将COMMIT_HASH的计算移到steps阶段确保在正确的目录下执行。steps { echo 拉取后端代码 git credentialsId: ${SLAVE_GIT_ID}, url: ${BACKEND_GIT_URL}, branch: master echo 计算镜像版本号 // 关键修复在 git 命令执行后立即在当前目录计算 COMMIT_HASH script { // 这里会在 /home/jenkins/backend-docker 目录下执行因为有 git 拉取所以一定有 .git env.COMMIT_HASH sh(returnStdout: true, script: git rev-parse --short HEAD).trim() env.BACK_FULL_IMAGE ${REGISTRY}/${BACK_NAMESPACE}/${BACK_APP_NAME}:${COMMIT_HASH} } echo 镜像地址${BACK_FULL_IMAGE} sh pwd ls -la | grep .git // 验证目录和git存在 修复要点说明移除了顶层environment中的COMMIT_HASH定义因为顶层无法预知节点目录直接执行 sh 100% 会失败。使用script块动态赋值在 git 拉取代码之后使用env.COMMIT_HASH ...动态定义环境变量。此时sh命令会继承当前node的路径即/home/jenkins/backend-docker这个目录下已经有 .git 文件了所以能成功执行。增加了目录验证sh pwd ls -la | grep .git可以帮你确认当前目录和 .git 文件是否存在排错更直观。知识点整理Jenkins 中env.COMMIT_HASH代码逐行详细解释这是Jenkins Pipeline (Jenkinsfile)里非常经典的一行代码核心作用是获取当前 Git 仓库最新提交的短哈希值并赋值给 Jenkins 环境变量。先把整行代码拆开从整体到局部彻底讲清楚env.COMMIT_HASHsh(returnStdout: true, script:git rev-parse --short HEAD).trim()整体功能一句话总结执行 Git 命令拿到当前代码最新提交的短 commit hash例如a7f3d92存入 Jenkins 环境变量COMMIT_HASH后续流水线可以直接使用。逐部分拆解解释①env.COMMIT_HASHenvJenkins 内置的环境变量对象所有流水线全局都能访问COMMIT_HASH自定义的环境变量名你可以改成GIT_COMMIT_SHORT等任意名称作用把后面计算出来的值存到这个全局变量里后续使用方式${env.COMMIT_HASH}或直接$COMMIT_HASH②sh( ... )Jenkins Pipeline 内置步骤执行 Shell 命令专门用来在 Jenkins 节点上运行 Linux/macOS 终端命令这里就是运行 Git 命令③returnStdout: truesh步骤的关键参数默认sh只执行命令不返回输出结果设置为true把 Shell 命令的输出结果作为字符串返回必须加否则拿不到 Git 哈希④script: git rev-parse --short HEAD真正执行的Git 核心命令逐段解释git rev-parseGit 内置命令用于解析 Git 内部对象这里解析提交记录--short关键参数→ 只返回短哈希默认 7 位如a7f3d92不加会返回完整 40 位哈希HEAD指向当前分支最新的一次提交命令效果输出当前最新 commit 的短哈希⑤.trim()Groovy 字符串方法作用去掉命令输出首尾的空白字符、换行符原因Shell 命令执行完会自带一个换行符\n不修剪会导致变量带换行拼接路径 / 文件名时报错常见问题与注意事项必须在 Git 仓库目录执行这行代码运行前必须先执行git checkout/git cloue,否则会报错not a git repository必须加.trim()不加会导致变量带换行拼接文件名、Docker 标签时必报错Windows 节点不兼容sh是Linux命令windows节点需要改成bat 或用 Git Bash总结这行代码 获取 Git 最新短提交哈希 存入 Jenkins 全局环境变量核心命令git rev-parse --short HEAD→ 取短哈希关键参数returnStdout: true返回结果.trim()去除换行用途给构建产物打标签、版本号、镜像标记、日志追踪