jenkins pipeline打包流程

news2024/12/18 18:07:17

Jenkins Pipeline 是 Jenkins 提供的一种用于持续集成和持续交付(CI/CD)的脚本化流程工具。它允许你通过编写一个 Jenkinsfile 文件来定义整个构建、测试和部署的流程。本文介绍打包springcloud项目,react项目为docker镜像

文章目录

    • 1.项目结构
    • 2.项目打包改造
      • 2.1. lhm-emp 模块pom.xml
      • 2.2. lhm-emp 模块Dockerfile
      • 2.3. lhm-web模块Dockerfile
    • 3. Jenkins docker pipeline编写
      • 3.1.GIT_CREDENTIALS_ID: git 认证参数
        • your-credentials-id
      • 3.2.pipeline编写
      • 3.3.执行打包任务
      • 3.4. 导入镜像
    • 4. 打包不同架构的基础image
      • 4.1. java
      • 4.2. nginx
    • 5. 注意
      • 5.1. 拉取http仓库 connect: connection refused"
      • 5.2. Jenkinsfile Pipeline 打包镜像缓慢解决办法
      • 5.3. unauthorized to access repository
    • 6. 打包增量
      • 6.1. docker打包增量例子

1.项目结构

├─Jenkinsfile    jenkinsfile打包脚本文件             
├─lhm-emp        微服务模块 emp服务
├─lhm-eureka     微服务模块 eureka服务
├─lhm-gateway    微服务模块 gateway服务
├─lhm-order      微服务模块 order服务
└─lhm-web        前端服务

项目地址 https://gitee.com/liuhaomin/springcloud

测试请求

## eureka
http://localhost:8100
## order
http://localhost:9000/api/order/info
## emp
http://localhost:9000/api/emp/info
## web
http://localhost:3000

2.项目打包改造

根pom.xml

<build>
        <finalName>${project.artifactId}</finalName>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                    <version>${spring-boot.version}</version>
                </plugin>
                <plugin>
                    <groupId>com.spotify</groupId>
                    <artifactId>dockerfile-maven-plugin</artifactId>
                    <version>${docker.plugin.version}</version>
                    <configuration>
                        <username>${docker.username}</username>
                        <password>${docker.password}</password>
                        <repository>${docker.registry.url}/${docker.namespace}/${project.artifactId}</repository>
                        <!--<tag>${os_tag}-${project.version}</tag>-->
                        <tag>${os_tag}${project.version}</tag>
                        <useMavenSettingsForAuth>true</useMavenSettingsForAuth>
                        <buildArgs>
                            <JAR_FILE>target/${project.build.finalName}.jar</JAR_FILE>
                        </buildArgs>
                        <skip>${dockerfile.skip}</skip>
                    </configuration>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>

2.1. lhm-emp 模块pom.xml

lhm-gateway,lhm-eureka,lhm-order 类似

  <build>
        <finalName>${project.artifactId}</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <mainClass>${emp.main.class}</mainClass>
                    <layout>ZIP</layout>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>

            <plugin>
                <groupId>com.spotify</groupId>
                <artifactId>dockerfile-maven-plugin</artifactId>
                <configuration>
                    <username>${docker.username}</username>
                    <password>${docker.password}</password>
                    <repository>${docker.registry.url}/${docker.namespace}/${project.artifactId}</repository>
                    <tag>${os_tag}${lhm.project.version}</tag>
                    <useMavenSettingsForAuth>true</useMavenSettingsForAuth>
                    <buildArgs>
                        <OS_ARCH>${os_arch}</OS_ARCH>
                        <CACHEFROM>${last_version}</CACHEFROM>
                        <TARGETPLATFORM>${os_arch.dockerimage}</TARGETPLATFORM>
                        <JAR_FILE>target/${project.build.finalName}.jar</JAR_FILE>
                        <EXPOSE_PORT>${emp.port}</EXPOSE_PORT>
                        <MAINCLASS>${emp.main.class}</MAINCLASS>
                    </buildArgs>
                    <skip>${dockerfile.skip}</skip>
                </configuration>
                <executions>
                    <execution>
                        <id>default</id>
                        <phase>package</phase>
                        <goals>
                            <goal>build</goal>
                            <goal>push</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

2.2. lhm-emp 模块Dockerfile

lhm-gateway,lhm-eureka,lhm-order 类似

ARG TARGETPLATFORM
ARG OS_ARCH

# 指定基础镜像,这是分阶段构建的前期阶段
FROM 192.168.56.10/lhm/openjdk:8-jdk-alpine as builder
# 执行工作目录
WORKDIR target
# 配置参数
ARG JAR_FILE=target/*.jar
# 将编译构建得到的jar文件复制到镜像空间中
COPY ${JAR_FILE} application.jar
RUN unzip application.jar

FROM --platform=$OS_ARCH $TARGETPLATFORM

ARG EXPOSE_PORT
ARG JAR_FILE
ARG MAINCLASS

ARG DEPENDENCY=target
COPY --from=builder ${DEPENDENCY}/META-INF /app/META-INF
COPY --from=builder ${DEPENDENCY}/BOOT-INF/lib /app/lib
COPY --from=builder ${DEPENDENCY}/BOOT-INF/classes /app

EXPOSE ${EXPOSE_PORT}

ARG CACHEFROM
LABEL description=" cache from ${CACHEFROM}"

ENV JAVA_OPTS ""
ENV AGENT_AFTER_JAR ""
ENV MAINCLASS ${MAINCLASS}

CMD java ${JAVA_OPTS} -Dspring.profiles.active=docker -Dservice_name=${MAINCLASS} -verbose:gc -XX:+PrintGCTimeStamps -XX:+PrintGCDetails -Xloggc:/opt/logs/jvm/gc.log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/opt/logs/jvm/dump.hprof -Djava.security.egd=file:/dev/./urandom -Denv=dev -Duser.timezone=GMT+08 ${AGENT_AFTER_JAR}  -cp app:app/lib2/*:app/lib/*  ${MAINCLASS}

2.3. lhm-web模块Dockerfile

ARG TARGETPLATFORM
ARG OS_ARCH

FROM --platform=$OS_ARCH $TARGETPLATFORM

ENV HTML_PATH=/usr/share/nginx/html

WORKDIR $HTML_PATH

COPY ./build $HTML_PATH

EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

3. Jenkins docker pipeline编写

3.1.GIT_CREDENTIALS_ID: git 认证参数

your-credentials-id

在这里插入图片描述

在这里插入图片描述

3.2.pipeline编写

pipeline {
    agent any
	options {
      // 最长保留90天,最多保留3个构建
	  buildDiscarder logRotator(artifactDaysToKeepStr: '', artifactNumToKeepStr: '', daysToKeepStr: '90', numToKeepStr: '3')
	}
	environment{
	   GIT_CREDENTIALS_ID="fd76875f-1862-43d4-adf4-6462e3b3c7f4"
	   SERVER_GIT_URL="https://gitee.com/liuhaomin/springcloud.git"
	   WEB_GIT_URL="https://gitee.com/liuhaomin/springcloud.git"
	   HARBOR_URL="192.168.56.10"
	   HARBOR_USERNAME="admin"
	   HARBOR_PASSWORD="Harbor12345"
	   // 192.168.56.10/lhm/lhm-web
	   HARBOR_NAMESPACE="lhm"
	   JAVACOMPILEIMAGE="192.168.56.10/lhm/openjdk:8-jdk-alpine"
       JAVA_OS_ARCH_DOCKERIMAGE="192.168.56.10/lhm/adoptopenjdk/openjdk8-openj9:alpine-slim"
	   NGINX_OS_ARCH_DOCKERIMAGE="192.168.56.10/lhm/nginx:1.26.1-alpine"
       OS_ARCH="linux/amd64"
       OS_TAG="x86"
	}
    parameters {
        listGitBranches(branchFilter: '.*', credentialsId: '${env.GIT_CREDENTIALS_ID}', defaultValue: 'master', listSize: '5', name: 'SERVER_BRANCH_NAME', quickFilterEnabled: false, remoteURL: 'https://gitee.com/liuhaomin/springcloud.git', selectedValue: 'DEFAULT', sortMode: 'NONE', tagFilter: '*', type: 'PT_BRANCH')
        listGitBranches(branchFilter: '.*', credentialsId: '${env.GIT_CREDENTIALS_ID}', defaultValue: 'master', listSize: '5', name: 'WEB_BRANCH_NAME', quickFilterEnabled: false, remoteURL: 'https://gitee.com/liuhaomin/springcloud.git', selectedValue: 'DEFAULT', sortMode: 'NONE', tagFilter: '*', type: 'PT_BRANCH')
        string(defaultValue: '1.0.1', description: '版本号', name: 'VERSION', trim: true)
	    booleanParam(defaultValue: false, description: '是否跳过构建', name: 'SKIP_BUILD')
        extendedChoice(description: '选择需要打包的服务模块(多选)', multiSelectDelimiter: ',', name: 'SERVICES', quoteValue: false, saveJSONParameterToFile: false,type: 'PT_CHECKBOX', value: 'lhm-eureka,lhm-gateway,lhm-emp,lhm-order,web-lhm-web',defaultValue: '',visibleItemCount: 5)
    }
    stages {
		stage('SERVER拉取代码') {
			when {
				expression {
					if (Boolean.valueOf("${SKIP_BUILD}")){
						echo "跳过SERVER拉取代码,直接打包镜像文件"
						return !Boolean.valueOf("${SKIP_BUILD}")
					}
					def services = "${SERVICES}"
					def index = services.indexOf('web-')
                        if (index > 0) {
                            services = services.substring(0, index - 1)
                        }
                    if( services.size() > 0 && index != 0) {
					    echo "包含服务,SERVER拉取代码"
						return true
					}
					echo "没有包含SERVER 跳过SERVER拉取代码"
					return false
				}
			}
			steps {
			    script {
					deleteDir()
					sh "ls"
					echo "SERVER检出代码..."
					def scmVars = checkout([
						$class:"GitSCM",
						branches:[[name:"${SERVER_BRANCH_NAME}"]],
						doGenerateSubmoduleConfigurations: false,
						gitTool: "Default",
						submoduleCfg: [],
						userRemoteConfigs:[[credentialsId:"${env.GIT_CREDENTIALS_ID}",url:"${env.SERVER_GIT_URL}"]]
					   ]
				   )
				   sh "echo '${scmVars}'"
				   sh "ls"
			   }
			}

		}
		stage('SERVER构建打包') {
			agent {
                docker{
					image 'maven:3.8-adoptopenjdk-8-openj9'
					reuseNode true
					args  '-v /root/.docker/config.json:/root/.docker/config.json -v /home/jenkins/repository:/root/.m2 -v /var/run/docker.sock:/var/run/docker.sock'
				}
			}
			when {
				expression {
					if (Boolean.valueOf("${SKIP_BUILD}")){
						echo "跳过SERVER构建打包,直接打包镜像文件"
						return !Boolean.valueOf("${SKIP_BUILD}")
					}
					def services = "${SERVICES}"
					def index = services.indexOf('web-')
                        if (index > 0) {
                            services = services.substring(0, index - 1)
                        }
                    if( services.size() > 0 && index != 0) {
					    echo "包含服务,SERVER构建打包"
						return true
					}
					echo "没有包含SERVER 跳过SERVER构建打包"
					return false
				}
			}
			steps {
				script {
					def moduleListStr = "${SERVICES}"
					echo "$moduleListStr"
					def index = moduleListStr.indexOf('web-')
					if (index > 0) {
						moduleListStr = moduleListStr.substring(0, index - 1)
					}
					def moduleList = moduleListStr.split(',')
					def count = moduleList.size()
					if (count <= 0) {
						echo "请选择构建模块..."
						sh 'exit 1'
					}

					def JAVACOMPILEIMAGE="${env.JAVACOMPILEIMAGE}"
					def JAVA_OS_ARCH_DOCKERIMAGE="${env.JAVA_OS_ARCH_DOCKERIMAGE}"
					def OS_ARCH="${env.OS_ARCH}"
                    def OS_TAG="${env.OS_TAG}"
					if("${OS_TAG}"=="x86"){
                        OS_TAG=""
                    }
					def moduleStr = moduleList.join(",:")

					echo "打包构建Version: ${VERSION}"
					sh "mvn -T 1C -pl :${moduleStr} -am clean package -Dmaven.test.skip=true -Ddockerfile.skip=false -Dlhm.project.version=${VERSION} -Dos_arch=${OS_ARCH} -Dos_tag=${OS_TAG} -Dos_arch.dockerimage=${JAVA_OS_ARCH_DOCKERIMAGE} -Djava.compileimage=${JAVACOMPILEIMAGE}"
					for (int i = 0; i < count; ++i) {
						def serviceName = "${moduleList[i]}"
						sh "docker tag ${env.HARBOR_URL}/${env.HARBOR_NAMESPACE}/${serviceName}:${OS_TAG}${VERSION} ${env.HARBOR_NAMESPACE}/${serviceName}:${OS_TAG}${VERSION}"
					}
                }
            }
        }
		stage('WEB拉取代码') {
			when {
				expression {
					if (Boolean.valueOf("${SKIP_BUILD}")){
						echo "跳过WEB拉取代码,直接打包镜像文件"
						return !Boolean.valueOf("${SKIP_BUILD}")
					}
					def services = "${SERVICES}"
					def index = services.indexOf('web-lhm-web')
                    if (index != -1 ) {
					    echo "包含web-lhm-web 打包WEB镜像"
						return true
					}
					echo "没有包含web-lhm-web 跳过WEB拉取代码"
					return false
				}
			}
			steps {
			    script {
					deleteDir()
					sh "ls"
					echo "WEB检出代码..."
					def scmVars = checkout([
						$class:"GitSCM",
						branches:[[name:"${WEB_BRANCH_NAME}"]],
						doGenerateSubmoduleConfigurations: false,
						gitTool: "Default",
						submoduleCfg: [],
						userRemoteConfigs:[[credentialsId:"${env.GIT_CREDENTIALS_ID}",url:"${env.WEB_GIT_URL}"]]
					   ]
					)
					sh "echo '${scmVars}'"
					sh "ls"
			   }
			}
		}
		stage('WEB构建打包') {
			agent {
                docker{
					image 'node:16-alpine'
					reuseNode true
					args  ''
				}
			}
			when {
				expression {
					if (Boolean.valueOf("${SKIP_BUILD}")){
						echo "跳过WEB构建打包,直接打包镜像文件"
						return !Boolean.valueOf("${SKIP_BUILD}")
					}
					def services = "${SERVICES}"
					def index = services.lastIndexOf('web-lhm-web')
                    if (index != -1 ) {
					    echo "包含web-lhm-web 打包WEB镜像"
						return true
					}
					echo "没有包含web-lhm-web 跳过WEB构建打包"
					return false
				}
			}
			steps {
			    script {
					echo "依赖安装..."
					sh "cd lhm-web && yarn config set registry https://registry.npmmirror.com/ && yarn install --network-concurrency 4 && yarn build"

					echo "打包构建Version: ${VERSION}"

					def NGINX_OS_ARCH_DOCKERIMAGE="${env.NGINX_OS_ARCH_DOCKERIMAGE}"
					def OS_ARCH="${env.OS_ARCH}"
                    def OS_TAG="${env.OS_TAG}"
					if("${OS_TAG}"=="x86"){
                        OS_TAG=""
                    }

//                     try {
//                         // 默认先打包增量,不成功再直接打包
//                         sh "docker pull ${env.HARBOR_URL}/${env.HARBOR_NAMESPACE}/lhm-web:${OS_TAG}${LAST_VERSION}"
//                         echo "基于[${env.HARBOR_URL}/${env.HARBOR_NAMESPACE}/lhm-web:${OS_TAG}${LAST_VERSION}]缓存构建"
//                         sh "cd lhm-web && docker build --cache-from ${env.HARBOR_URL}/${env.HARBOR_NAMESPACE}/lhm-web:${OS_TAG}${LAST_VERSION} --build-arg TARGETPLATFORM=${NGINX_OS_ARCH_DOCKERIMAGE} --build-arg OS_ARCH=${OS_ARCH} -t ${env.HARBOR_URL}/${env.HARBOR_NAMESPACE}/lhm-web:${OS_TAG}${VERSION_NO} . && docker images"
//                     } catch (err) {
//                         def error = "${e.toString()}"
//                         echo "不走缓存构建,没有找到[${env.HARBOR_URL}/${env.HARBOR_NAMESPACE}/lhm-web:${OS_TAG}${LAST_VERSION}]镜像"
//                         if(error.contains("not found")){
// 					        sh "cd lhm-web && docker build --build-arg TARGETPLATFORM=${NGINX_OS_ARCH_DOCKERIMAGE} --build-arg OS_ARCH=${OS_ARCH} -t ${env.HARBOR_URL}/${env.HARBOR_NAMESPACE}/lhm-web:${OS_TAG}${VERSION} .&& docker images"
//                         } else {
//                             throw err
//                         }
//                     }
                    // 登录一下,防止找到不基础镜像
		            sh "docker login ${env.HARBOR_URL}  -u ${env.HARBOR_USERNAME} -p ${env.HARBOR_PASSWORD}"
                    sh "cd lhm-web && docker build --build-arg TARGETPLATFORM=\'${NGINX_OS_ARCH_DOCKERIMAGE}\' --build-arg OS_ARCH=${OS_ARCH} -t ${env.HARBOR_URL}/${env.HARBOR_NAMESPACE}/lhm-web:${OS_TAG}${VERSION} .&& docker images"

					sh "docker tag ${env.HARBOR_URL}/${env.HARBOR_NAMESPACE}/lhm-web:${OS_TAG}${VERSION} ${env.HARBOR_NAMESPACE}/lhm-web:${OS_TAG}${VERSION}"
					// 登录harbor docker 仓库中心
					echo "----<<<< 登录harbor docker 仓库中心 >>>>-----"
					sh "docker login ${env.HARBOR_URL}  -u ${env.HARBOR_USERNAME} -p ${env.HARBOR_PASSWORD}"
					// 推送镜像到harhor docker 仓库中心
					echo "----<<<< 推送镜像到harhor docker 仓库中心 >>>>-----"
					sh "docker push ${env.HARBOR_URL}/${env.HARBOR_NAMESPACE}/lhm-web:${OS_TAG}${VERSION}"
				}
            }
        }
		stage('镜像打包') {
			steps {
			    script {
                    def OS_TAG="${env.OS_TAG}"
					if("${OS_TAG}"=="x86"){
                        OS_TAG=""
                    }
					echo "${SERVICES}"
				    def serviceListStr = "${SERVICES}"
					if (serviceListStr.isEmpty()) {
                        echo "请选择构建模块..."
						sh 'exit 1'
                    }
					def batchImages = []
					serviceListStr = serviceListStr.replace("web-","")
					def serviceList = serviceListStr.split(',')
                    def count = serviceList.size()
                    def fullFolderstr = "${WORKSPACE}/full/${VERSION}/"
                    sh "mkdir -p ${fullFolderstr} && cd ${fullFolderstr}"
                    echo "use version: ${VERSION}"
                    echo "OS_TAG: ${OS_TAG}"
                    sh "cd ${fullFolderstr} && touch images-load.sh && touch images-list.txt && echo '#!/bin/sh' > images-load.sh && echo 'echo \"==== starting to load images ====\"' >> images-load.sh && echo 'echo \"====  服务导入镜像 ====\"' >> images-load.sh"
                    sh "cd ${fullFolderstr} && echo ' ' > images-list.txt"

					sh "docker login ${env.HARBOR_URL}  -u ${env.HARBOR_USERNAME} -p ${env.HARBOR_PASSWORD}"
					for (int i = 0; i < count; ++i) {
                        def serviceName = "${serviceList[i]}"
						sh "docker pull ${env.HARBOR_URL}/${env.HARBOR_NAMESPACE}/${serviceName}:${OS_TAG}${VERSION}"
                        sh "docker tag ${env.HARBOR_URL}/${env.HARBOR_NAMESPACE}/${serviceName}:${OS_TAG}${VERSION} ${env.HARBOR_NAMESPACE}/${serviceName}:${OS_TAG}${VERSION}"
                        batchImages.add("${env.HARBOR_NAMESPACE}/${serviceName}:${OS_TAG}${VERSION}")
                        sh "cd ${fullFolderstr} && echo '- ${env.HARBOR_NAMESPACE}/${serviceName}:${OS_TAG}${VERSION}' >> images-list.txt"
                    }
                    def batchImagesStr = batchImages.join(" ")
                    def grepVersion = "${VERSION}".replaceAll(".", ".")
					sh "cd ${fullFolderstr} && echo 'docker load -i app.tar.gz' >> images-load.sh"
                    sh "cd ${fullFolderstr} && echo 'echo \"==== 查看服务镜像 ====\"' >> images-load.sh && echo 'docker images | grep -E ${grepVersion}' >> images-load.sh && echo 'echo \"==== end to load images ====\"' >> images-load.sh"

					sh "docker images | grep -E ${grepVersion}"
					// 打包全量
					sh "docker save ${batchImagesStr}|gzip > ${fullFolderstr}/app.tar.gz"
                    //sh "cd ${WORKSPACE}/full && ls && rm -rf ${OS_TAG}${VERSION}.zip && zip -r ${OS_TAG}${VERSION}.zip ${VERSION}/* && cp ${WORKSPACE}/full/${OS_TAG}${VERSION}.zip ${WORKSPACE}"
                    sh "cd ${WORKSPACE}/full && ls && rm -rf ${OS_TAG}${VERSION}.zip && tar -czvf ${OS_TAG}${VERSION}.tar.gz ${VERSION}/* && cp ${WORKSPACE}/full/${OS_TAG}${VERSION}.tar.gz ${WORKSPACE}"

					try {
						// -f :显示时进行过滤  “dangling=true”: 表示过滤并显示悬挂状态的镜像,即没有被标签引用或者被其他层依赖的镜像  -q :只显示image id
						//sh "docker images -q -f dangling=true | xargs docker rmi -f"
						// 清理打包的镜像
						sh "docker images --format '{{.Repository}}:{{.Tag}}' | grep '${env.HARBOR_NAMESPACE}/' | xargs docker rmi -f"
					} catch (err) {}
					
                    archiveArtifacts artifacts: '*.tar.gz', onlyIfSuccessful: true
                    echo "==== starting to export images ===="
                    echo "请下载Last Successful Artifacts构建成品!!!"
				}
            }
        }

    }
}


在这里插入图片描述

3.3.执行打包任务

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

3.4. 导入镜像

下载后执行

tar -xzvf 1.0.0.tar.gz
cd 1.0.0
bash images-load.sh

4. 打包不同架构的基础image

推荐一部分

4.1. java

# x86_64
adoptopenjdk/openjdk8-openj9:alpine-slim
# aarch64
arm64v8/adoptopenjdk:8-jre-openj9

4.2. nginx

# x86_64
nginx:1.26.1-alpine
# aarch64
nginx:1.26.1-alpine

5. 注意

5.1. 拉取http仓库 connect: connection refused"

[ERROR] Failed to execute goal com.spotify:dockerfile-maven-plugin:1.4.13:build (default) on project lhm-eureka: Could not pull cache-from image: Request error: POST unix://localhost:80/images/create?fromImage=192.168.56.10%2Flhm%2Flhm-eureka&tag=x86_641.0.0: 500, body: {"message":"Get https://192.168.56.10/v2/: dial tcp 192.168.56.10:443: connect: connection refused"} -> [Help 1]

在这里插入图片描述

解决办法:

设置docker的仓库地址

vi /etc/docker/daemon.json
新增 registry-mirrors:["http://192.168.56.10"],
"insecure-registries" : ["192.168.56.10:5000", "0.0.0.0/0"]

insecure-registries是Docker中的一个配置选项,涉及容器镜像的安全拉取。

  • 定义与用途‌:
    指允许Docker从不安全(即未使用HTTPS协议的)注册中心拉取镜像的列表。默认情况下,Docker为了安全考虑,只允许从使用HTTPS的注册中心拉取镜像。
  • 配置方式‌:
    在Docker配置文件(如/etc/docker/daemon.json)中,通过添加"insecure-registries"字段并指定一个或多个注册中心地址来配置。例如,"insecure-registries" : ["my-registry.local:5000"]允许从不安全的my-registry.local:5000拉取镜像。

5.2. Jenkinsfile Pipeline 打包镜像缓慢解决办法

  • 将所有使用的docker镜像推送至自己的私有仓库(防止拉取其他镜像缓慢)

DockerFile 文件

FROM openjdk:8-jdk-alpine as builder
# 执行工作目录
WORKDIR target

在这里插入图片描述

上述文件比下面的文件缓慢接近20多倍

FROM 192.168.56.10/lhm/openjdk:8-jdk-alpine
# 执行工作目录
WORKDIR target

在这里插入图片描述

5.3. unauthorized to access repository

[ERROR] Failed to execute goal com.spotify:dockerfile-maven-plugin:1.4.13:build (default) on project lhm-eureka: Could not build image: unauthorized: unauthorized to access repository: lhm/openjdk, action: pull: unauthorized to access repository: lhm/openjdk, action: pull -> [Help 1]

解决办法

docker login 192.168.56.10 admin Harbor12345
或者 
新增 -v /root/.docker/config.json:/root/.docker/config.json 

 docker{
  image '192.168.56.10/lhm/maven:3.8-adoptopenjdk-8-openj9'
  reuseNode true
  args  '-v /root/.docker/config.json:/root/.docker/config.json -v /home/jenkins/repository:/root/.m2 -v /var/run/docker.sock:/var/run/docker.sock'
}

6. 打包增量

打包增量详细解释

6.1. docker打包增量例子

打包增量可以使用springcloud increment 分支
在这里插入图片描述
jar需要单独替换为下面文件中的jar

增强了功能

  • 打印了一些日志
  • 如果需要cachefrom 的镜像不存在就直接打包,忽略当前的缓存打包

https://docs.docker.com/reference/api/engine/version/v1.40/#tag/Image/operation/ImageBuild
在这里插入图片描述

在这里插入图片描述

修改了BuildMojo.java

@Nullable
  static String buildImage(@Nonnull DockerClient dockerClient,
                           @Nonnull Log log,
                           boolean verbose,
                           @Nonnull Path contextDirectory,
                           @Nullable Path dockerfile,
                           @Nullable String repository,
                           @Nonnull String tag,
                           boolean pullNewerImage,
                           boolean noCache,
                           @Nullable Map<String,String> buildArgs,
                           @Nullable List<String> cacheFrom,
                           boolean squash)
      throws MojoExecutionException, MojoFailureException {

    log.info(MessageFormat.format("Building Docker context {0}", contextDirectory));
    log.info(MessageFormat.format("Building Docker noCache {0}", noCache));
    log.info(MessageFormat.format("Building Docker cacheFrom {0}", cacheFrom.toString()));

    requireValidDockerFilePath(log, contextDirectory, dockerfile);

    final ArrayList<DockerClient.BuildParam> buildParameters = new ArrayList<>();
    if (dockerfile != null) {
      buildParameters.add(DockerClient.BuildParam.dockerfile(
          contextDirectory.relativize(dockerfile)));
    }

    final LoggingProgressHandler progressHandler = new LoggingProgressHandler(log, verbose);
    if (pullNewerImage) {
      buildParameters.add(DockerClient.BuildParam.pullNewerImage());
    }
    if (noCache) {
      buildParameters.add(DockerClient.BuildParam.noCache());
    }

    if (buildArgs != null && !buildArgs.isEmpty()) {
      buildParameters.add(new DockerClient.BuildParam("buildargs", encodeBuildParam(buildArgs)));
    }

    if (cacheFrom != null && !noCache) {
      final List<String> cacheFromExistLocally = new ArrayList<>();
      for (String image : cacheFrom) {
        try {
          if (pullNewerImage || !imageExistLocally(dockerClient, image)) {
            dockerClient.pull(image);
          }
          log.info(MessageFormat.format("Build will use image {0} for cache-from", image));
          cacheFromExistLocally.add(image);
        } catch (Exception e) {
          log.warn(MessageFormat.format(
                  "Image {0} not found, build will not use it for cache-from", image));
        }
      }
      if (!cacheFromExistLocally.isEmpty()) {
        buildParameters.add(new DockerClient.BuildParam("cachefrom",encodeBuildParam(cacheFromExistLocally)));
        log.info("buildParameters.add for cachefrom "+ cacheFromExistLocally.toString());
      }
    }

    if (squash) {
      buildParameters.add(new DockerClient.BuildParam("squash", encodeBuildParam(squash)));
    }

    final DockerClient.BuildParam[] buildParametersArray =
        buildParameters.toArray(new DockerClient.BuildParam[buildParameters.size()]);

    log.info(""); // Spacing around build progress
    try {
      if (repository != null) {
        if (!validateRepository(repository)) {
          throw new MojoFailureException(
                  "Repo name \""
                          + repository
                          + "\" must contain only lowercase, numbers, '-', '_' or '.'.");
        }

        final String name = formatImageName(repository, tag);
        log.info(MessageFormat.format("Image will be built as {0}", name));
        log.info(""); // Spacing around build progress
        dockerClient.build(contextDirectory, name, progressHandler, buildParametersArray);
      } else {
        log.info("Image will be built without a name");
        log.info(""); // Spacing around build progress
        dockerClient.build(contextDirectory, progressHandler, buildParametersArray);
      }
    } catch (DockerException | IOException | InterruptedException e) {
      throw new MojoExecutionException("Could not build image", e);
    }
    log.info(""); // Spacing around build progress

    return progressHandler.builtImageId();
  }

在这里插入图片描述

在这里插入图片描述

打包有下面这个就代表使用了缓存
在这里插入图片描述在这里插入图片描述

在这里插入图片描述

结果
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2261723.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【容器】k8s学习笔记原理详解(十万字超详细)

Pod详解 Pod介绍 Pod结构 每个Pod中都可以包含一个或者多个容器&#xff0c;这些容器可以分为两类&#xff1a; 用户程序所在的容器&#xff0c;数量可多可少Pause容器&#xff0c;这是每个Pod都会有的一个根容器&#xff0c;它的作用有两个&#xff1a; 可以以它为依据&am…

用.Net Core框架创建一个Web API接口服务器

我们选择一个Web Api类型的项目创建一个解决方案为解决方案取一个名称我们这里选择的是。Net 8.0框架 注意&#xff0c;需要勾选的项。 我们找到appsetting.json配置文件 appsettings.json配置文件内容如下 {"Logging": {"LogLevel": {"Default&quo…

多音轨视频使用FFmpeg删除不要音轨方法

近期给孩子找宫崎骏动画&#xff0c;但是有很多是多音轨视频但是默认的都是日语&#xff0c;电视上看没办法所以只能下载后删除音轨文件只保留中文。 方法分两步&#xff0c;先安装FFmpeg在转文件即可。 第一步FFmpeg安装 FFmpeg是一个开源项目&#xff0c;包含了处理视频的…

Ubuntu22.04切换gcc版本教程

在编译安装程序的时候,由于gcc版本过高,导致编译无法通过,需要降低gcc版本。 一、安装gcc版本 根据自己的需求安装gcc版本。 sudo apt update sudo apt install gcc-10 g++-10二、切换gcc版本 sudo update-alternatives --install /usr/bin/gcc gcc

[SZ901] JTAG合并功能(类似FPGA菊花链)

SZ901 JTAG支持将JTAG端口组合&#xff0c;最多将四个JTAG变成一个 设置如下 Vivado 识别结果如下 两块板子&#xff0c;变成一组&#xff0c;&#xff0c;可以同时抓取信号&#xff0c;调试&#xff01; SZ901 已上架淘宝&#xff0c;搜素“SZ901”哦

【收藏】Cesium 限制相机倾斜角(pitch)滑动范围

1.效果 2.思路 在项目开发的时候&#xff0c;有一个需求是限制相机倾斜角&#xff0c;也就是鼠标中键调整视图俯角时&#xff0c;不能过大&#xff0c;一般 pitch 角度范围在 0 至 -90之间&#xff0c;-90刚好为正俯视。 在网上查阅了很多资料&#xff0c;发现并没有一个合适的…

如何解决samba服务器共享文件夹不能粘贴文件

sudo vim /etc/samba/smb.conf在samba的配置文件中增加一个选项 writable yes重启Samba服务以使更改生效&#xff1a; sudo service smbd restart

数据结构简介:结构创造效率

一、数据结构的本质 数据结构是组织大量数据的方法&#xff08;data structures&#xff1a;methods of organizing large amounts of data &#xff09;。 根据这个定义&#xff0c;一条数据&#xff0c;就不能构成数据结构。 因为结构是数据与数据之间的关联&#xff0c;…

【经验分享】容器云运维的知识点

最近忙于备考没关注&#xff0c;有次点进某小黄鱼发现首页出现了我的笔记还被人收费了 虽然我也卖了一些资源&#xff0c;但我以交流、交换为主&#xff0c;笔记都是免费给别人看的 由于当时刚刚接触写的并不成熟&#xff0c;为了避免更多人花没必要的钱&#xff0c;所以决定公…

Linux系列之如何更换Centos yum源?

环境 Centos7Xshell7 问题描述 最近安装了一个虚拟机&#xff0c;准备用来学习&#xff0c;不过使用yum命令安装一些软件&#xff0c;不过使用这个命令时候&#xff0c;提示 Cannot find a valid baseurl for repo: base/7/x86_64&#xff0c;Could not retrieve mirrorlis…

RabbitMQ如何构建集群?

大家好&#xff0c;我是锋哥。今天分享关于【RabbitMQ如何构建集群&#xff1f;】面试题。希望对大家有帮助&#xff1b; RabbitMQ如何构建集群&#xff1f; 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 在RabbitMQ中&#xff0c;集群&#xff08;Cluster&#x…

负载均衡oj项目:介绍

目录 项目介绍 项目演示 项目介绍 负载均衡oj是一个基于bs模式的项目。 用户使用浏览器向oj模块提交代码&#xff0c;oj模块会在所有在线的后端主机中选择一个负载情况最低的主机&#xff0c;将用户的代码提交给该主机&#xff0c;该主机进行编译运行&#xff0c;将结果返回…

第8章 搬移特性

8.1 搬移函数 模块化是优秀软件设计的核心所在&#xff0c;好的模块化能够让我在修改程序时只需理解程序的一小部分。为了设计出高度模块化的程序&#xff0c;我得保证互相关联的软件要素都能集中到一块&#xff0c;并确保块与块之间的联系易于查找、直观易懂。同时&#xff0c…

rust的axux框架开启负载均衡和重启自身的方法-会议签到的调优

开启负载均衡和重启自身 更换axum后台的意外解决的尝试在caddy反代,使用负载均衡,加多一个节点axum主程序 ip映射信息做全局共享axum重启自身刷新全局共享配置 前期刚实现了rust的后台关键业务.结果出现了两类大问题停止服务.在正用着的时候,出现很多意外,真是刺激… 更换axum…

Spring源码分析之BeanFactory接口的解析

前言: 在我们的前两篇文章当中我们看完之后其实我们都会发现当我们进行相关的重要的行为的时候如我们看到的GetBean或者在Register方法的时候会出现BeanFactroy进行调用那么这个时候我们就会产生一个疑惑这个到底是什么为什么这么重要,在我没有说的时候我们从字面上进行一个简单…

【zlm】 webrtc源码讲解三(总结)

目录 setsdp onwrite ​编辑 play 参考 setsdp onwrite play 参考 【zlm】 webrtc源码讲解_zlm webrtc-CSDN博客 【zlm】 webrtc源码讲解&#xff08;二&#xff09;_webrtc 源码-CSDN博客

电子应用设计方案-56:智能书柜系统方案设计

智能书柜系统方案设计 一、引言 随着数字化时代的发展和人们对知识获取的需求增加&#xff0c;智能书柜作为一种创新的图书管理和存储解决方案&#xff0c;能够提供更高效、便捷和个性化的服务。本方案旨在设计一款功能齐全、智能化程度高的智能书柜系统。 二、系统概述 1. 系…

Spring Boot 性能提升的核武器,速度提升 500%!

虚拟线程是 Java 21 引入的一个新特性&#xff0c;用于简化并发编程。它与传统的操作系统线程相比&#xff0c;具有显著的优势&#xff1a; 轻量级&#xff1a;虚拟线程由 JVM 管理&#xff0c;而非操作系统&#xff0c;因此它们的内存占用和创建成本远低于传统线程。理论上&am…

【5G】5G 无线协议 Radio Protocols(一)

长期演进&#xff08;LTE&#xff09;无线电协议主要设计用于通过扁平架构提供PS服务&#xff0c;相比之前的代际&#xff0c;这代表了一个重大改进&#xff0c;它消除了支持电路交换&#xff08;CS&#xff09;服务和复杂架构中固有的复杂性。许多原始的LTE原则自第8版以来一直…

实现按键按下(低电平)检测到下降沿

按照流程进行编程 步骤1&#xff1a; 初始化函数 包括时基工作参数配置 输入通道配置 更新中断使能 使能捕获、捕获中断及计数器 HAL_TIM_IC_Init(&ic_handle) //时基参数配置 HAL_TIM_IC_ConfigChannel(&ic_handle,&ic_config,TIM_CHANNEL_2) //输…