DevOps系列文章 之GitLabCI模板库的流水线
目录结构,jobs目录用于存放作业模板。templates目录用于存放流水线模板。这次使用
default-pipeline.yml
作为所有作业的基础模板。
作业模板
作业分为Build、test、codeanalysis、artifactory、deploy部分,在每个作业中配置了rules功能开关,由变量控制最终作业的运行。
jobs/build.yml 构建作业模板
包含两个作业模板,分别是普通的构建模板(maven/npm/gradle)和docker 镜像构建模板。
## build相关作业.build:stage: buildscript: - |${BUILD_SHELL}variables:GIT_CHECKOUT: "true"rules:- if: " $RUN_PIPELINE_BUILD == 'no' "when: never- when: always## 构建镜像
.build-docker:stage: buildimagescript:- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWD $CI_REGISTRY- docker build -t ${IMAGE_NAME} -f ${DOCKER_FILE_PATH} .- docker push ${IMAGE_NAME} - docker rmi ${IMAGE_NAME} rules:- if: " $RUN_BUILD_IMAGE == 'no' "when: never- when: always
jobs/test.yml 测试作业模板
主要用于运行项目单元测试,例如maven、gradle、npm单元测试。
#单元测试
.test:stage: testscript:- $TEST_SHELLartifacts:reports:junit: ${JUNIT_REPORT_PATH}rules:- if: " $RUN_PIPELINE_TEST == 'no' "when: never- when: always
jobs/codeanalysis.yml 代码扫描模板
包含两个作业模板,分别为扫描作业和获取扫描结果。这里面将扫描参数进行了分类,通用的项目参数、特殊的合并请求参数、自定义的项目参数。
##代码扫描
##
##
##.code_analysis:variables:GLOBAL_PROJECT_ARGS: "-Dsonar.projectKey=${CI_PROJECT_NAME} -Dsonar.projectName=${CI_PROJECT_NAME} -Dsonar.projectVersion=${CI_COMMIT_REF_NAME} -Dsonar.projectDescription=${CI_PROJECT_TITLE}"GLOBAL_SERVER_ARGS: "-Dsonar.ws.timeout=30 -Dsonar.links.homepage=${CI_PROJECT_URL} -Dsonar.host.url=${SONAR_SERVER_URL} -Dsonar.login=${SONAR_SERVER_LOGIN}-Dsonar.sourceEncoding=UTF-8 "GLOBAL_MR_ARGS: " -Dsonar.pullrequest.key=${CI_MERGE_REQUEST_IID} -Dsonar.pullrequest.branch=${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME} -Dsonar.pullrequest.base=${CI_MERGE_REQUEST_TARGET_BRANCH_NAME} -Dsonar.gitlab.ref_name=${CI_COMMIT_REF_NAME} -Dsonar.gitlab.commit_sha=${CI_COMMIT_SHA} -Dsonar.gitlab.project_id=${CI_PROJECT_PATH} -Dsonar.pullrequest.gitlab.repositorySlug=${CI_PROJECT_ID} "MULTI_BRANCH_ARGS: "-Dsonar.branch.name=${CI_COMMIT_REF_NAME}"stage: code_analysisscript:- echo ${GLOBAL_PROJECT_ARGS} ${GLOBAL_SERVER_ARGS} ${SONAR_SCAN_ARGS} ${GLOBAL_MR_ARGS}#sonar-scanner $GLOBAL_PROJECT_ARGS $GLOBAL_SERVER_ARGS $SCAN_JAVA_ARGS- |if [ $CI_PIPELINE_SOURCE == 'merge_request_event' ] thenecho "sonar-scanner ${GLOBAL_PROJECT_ARGS} ${GLOBAL_SERVER_ARGS} ${SONAR_SCAN_ARGS} " sonar-scanner ${GLOBAL_PROJECT_ARGS} ${GLOBAL_SERVER_ARGS} ${SONAR_SCAN_ARGS} else echo "sonar-scanner ${GLOBAL_PROJECT_ARGS} ${GLOBAL_SERVER_ARGS} ${SONAR_SCAN_ARGS} ${MULTI_BRANCH_ARGS}"sonar-scanner ${GLOBAL_PROJECT_ARGS} ${GLOBAL_SERVER_ARGS} ${SONAR_SCAN_ARGS} ${MULTI_BRANCH_ARGS}fi rules:- if: " $RUN_CODE_ANALYSIS == 'no' "when: never- when: always#### 获取代码扫描结果
.get_analysis_result:stage: get_analysis_resultscript:- |SONAR_REPORT_URL=$(grep "ceTaskUrl" .scannerwork/report-task.txt | awk -F = '{OFS="=";print $2,$3}')echo ${SONAR_REPORT_URL}for i in {1..10}docurl -k -u "${SONAR_SERVER_LOGIN}":"" ${SONAR_REPORT_URL} -o sonar_result.txt -sgrep '"status":"SUCCESS"' sonar_result.txt && SONAR_SCAN_RESULT='SUCCESS'if [ ${SONAR_SCAN_RESULT} == 'SUCCESS' ]thenecho "${SONAR_SCAN_RESULT}"SONAR_SCAN_RESULT=SUCCESScurl -k -u "${SONAR_SERVER_LOGIN}":"" "${SONAR_SERVER_URL}/api/qualitygates/project_status?projectKey=$CI_PROJECT_NAME&branch=$CI_COMMIT_REF_NAME" -o result.txt -secho "result info ---->>>>>"cat result.txtresult=`cat result.txt | awk -F ':' '{print $3}' | awk -F '"' '{print$2}'`echo $resultif [ $result == 'ERROR' ] then echo "${result}"exit 122break;elseecho "success!"break;fielseSONAR_SCAN_RESULT='ERROR'echo "第$i次获取结果信息,不是成功状态,睡眠10秒!"cat sonar_result.txtsleep 10fidonerules:- if: " $RUN_CODE_ANALYSIS == 'no' "when: never- when: always
jobs/artifactory.yml 制品管理作业
包含两个作业,制品上传与下载。使用artifactory制品库接口。
## 制品库相关
##.deploy-artifact:stage: deploy-artifactscript:- echo "curl -u${ARTIFACT_USER}:${ARTIFACT_PASSWD} -T ${ARTIFACT_PATH} $ARTIFACTORY_URL/$ARTIFACTORY_NAME/$TARGET_FILE_PATH/$TARGET_ARTIFACT_NAME"- curl -u${ARTIFACT_USER}:${ARTIFACT_PASSWD} -T ${ARTIFACT_PATH} "$ARTIFACTORY_URL/$ARTIFACTORY_NAME/$TARGET_FILE_PATH/$TARGET_ARTIFACT_NAME"rules:- if: " $RUN_DEPLOY_ARTIFACTS == 'no' "when: never- when: always.down-artifact:stage: down-artifactscript:- curl -u${ARTIFACT_USER}:${ARTIFACT_PASSWD} -O "$ARTIFACTORY_URL/$ARTIFACTORY_NAME/$TARGET_FILE_PATH/$TARGET_ARTIFACT_NAME"- ls
jobs/deploy.yml 发布作业模板
发布基于k8s的发布和回滚配置。
## 应用发布## 使用kubectl镜像发布
.deploy_k8s:stage: deployscript:- echo $KUBE_TOKEN- kubectl config set-cluster my-cluster --server=${KUBE_URL} --certificate-authority="${KUBE_CA_PEM_FILE}"- kubectl config set-credentials admin --token=${KUBE_TOKEN}- ls -a - sed -i "s#__namespace__#${NAMESPACE}#g" ${DEPLOY_FILE}- sed -i "s#__appname__#${APP_NAME}#g" ${DEPLOY_FILE}- sed -i "s#__containerport__#${CONTAINER_PORT}#g" ${DEPLOY_FILE} - sed -i "s#__nodeport__#${NODE_PORT}#g" ${DEPLOY_FILE} - sed -i "s#__imagename__#${IMAGE_NAME}#g" ${DEPLOY_FILE} - sed -i "s#__CI_ENVIRONMENT_SLUG__#${CI_ENVIRONMENT_SLUG}#g" ${DEPLOY_FILE}- sed -i "s#__CI_PROJECT_PATH_SLUG__#${CI_PROJECT_PATH_SLUG}#g" ${DEPLOY_FILE}- sed -i "s#__ingressdomain__#${ENV_URL}#g" ${DEPLOY_FILE}- cat ${DEPLOY_FILE}- "kubectl create secret docker-registry ${APP_NAME} \--docker-server=${CI_REGISTRY} \--docker-username=$CI_REGISTRY_USER \--docker-password=${CI_REGISTRY_PASSWD} \--docker-email=test@test.com -n ${NAMESPACE} || echo 'secrets already exists'"- kubectl apply -f ${DEPLOY_FILE}rules:- if: " $RUN_DEPLOY_K8S == 'no'"when: never- when: manualenvironment:name: "${ENV_NAME}"url: "http://${ENV_NAME}.${CI_PROJECT_NAMESPACE}.${CI_PROJECT_NAME}.devops.com"## 回滚
.rollout_k8s:stage: deployscript:- rm -rf $HOME/.kube- kubectl config set-cluster my-cluster --server=${KUBE_URL} --certificate-authority="${KUBE_CA_PEM_FILE}"- kubectl config set-credentials admin --token=${KUBE_TOKEN}- kubectl rollout history deployment ${APP_NAME} -n ${NAMESPACE}- kubectl rollout undo deployment ${APP_NAME} -n ${NAMESPACE}rules:- if: " $RUN_DEPLOY_K8S == 'no' "when: never- when: manualenvironment:name: "${ENV_NAME}"action: stop
default流水线模板
templates/default-pipeline.yml 模板分成个部分
- include导入作业模板
- variables 定义全局变量
- workflow 定义流水线控制
- jobs 构建与发布作业
include导入作业模板
include:- project: 'cidevops/cidevops-newci-service'ref: masterfile: 'jobs/build.yml'- project: 'cidevops/cidevops-newci-service'ref: masterfile: 'jobs/test.yml'- project: 'cidevops/cidevops-newci-service'ref: masterfile: 'jobs/codeanalysis.yml'- project: 'cidevops/cidevops-newci-service'ref: masterfile: 'jobs/deploy.yml'- project: 'cidevops/cidevops-newci-service'ref: masterfile: 'jobs/artifactory.yml'
variables 定义全局变量
variables:## 全局配置GIT_CLONE_PATH: ${CI_BUILDS_DIR}/builds/${CI_PROJECT_NAMESPACE}/${CI_PROJECT_NAME}/${CI_PIPELINE_ID} GIT_CHECKOUT: "false"CACHE_DIR: ""## 作业控制RUN_PIPELINE_BUILD: "" #是否运行构建 yes/no RUN_PIPELINE_TEST: "" #是否运行测试 yes/no RUN_CODE_ANALYSIS: "" #是否代码扫描 yes/no RUN_BUILD_IMAGE: "" #是否生成镜像 yes/noRUN_DEPLOY_ARTIFACTS: "" #是否上传制品 yes/noRUN_DEPLOY_K8S: "" #是否发布K8S yes/no## 依赖容器镜像BUILD_IMAGE: ""CURL_IMAGE: "curlimages/curl:7.70.0"SONAR_IMAGE: "sonarsource/sonar-scanner-cli:latest"KUBECTL_IMAGE: "lucj/kubectl:1.17.2"## 构建测试参数MAVEN_OPTS: "" #maven构建参数 GRADLE_OPTS: "" #gradle构建参数BUILD_SHELL: '' #构建命令## 单元测试参数TEST_SHELL : 'mvn test --settings=./settings.xml ' #测试命令JUNIT_REPORT_PATH: 'target/surefire-reports/TEST-*.xml' #单元测试报告## 代码扫描SONAR_SOURCE_DIR : "src" #项目源码目录SONAR_SERVER_URL: "http://192.168.1.200:30090" #SonarQube服务器信息SONAR_SERVER_LOGIN: "ee2bcb37deeb6dfe3a07fe08fb529559b00c1b7b" #Sonar Token最好在项目中定义。SONAR_SCAN_ARGS: "-Dsonar.sources=${SONAR_SOURCE_DIR}" #项目扫描参数## 构建镜像CI_REGISTRY: 'registry.cn-beijing.aliyuncs.com' #镜像仓库地址 CI_REGISTRY_USER: 'xxxxxx' #仓库用户信息#CI_REGISTRY_PASSWD: 'xxxxxxxx.' #仓库用户密码IMAGE_NAME: "${CI_REGISTRY}/${CI_PROJECT_PATH}:${CI_COMMIT_REF_NAME}-${CI_COMMIT_SHORT_SHA}" #镜像名称DOCKER_FILE_PATH: "./Dockerfile" #Dockerfile位置## 上传制品库(artifactory)ARTIFACTORY_URL: "http://192.168.1.200:30082/artifactory" #制品库地址ARTIFACTORY_NAME: "${CI_PROJECT_NAMESPACE}" #制品库名称ARTIFACT_PACKAGE: "jar" #制品类型ARTIFACT_PATH: "target/*.${ARTIFACT_PACKAGE}" #制品位置TARGET_FILE_PATH: "${CI_PROJECT_NAMESPACE}/${CI_PROJECT_NAME}/${CI_COMMIT_REF_NAME}-${CI_COMMIT_SHORT_SHA}" #目标制品位置(目录结构)TARGET_ARTIFACT_NAME: "${CI_PROJECT_NAME}-${CI_COMMIT_REF_NAME}-${CI_COMMIT_SHORT_SHA}.${ARTIFACT_PACKAGE}" #目标制品名称## 部署应用k8sAPP_NAME: "$CI_PROJECT_NAME" #应用名称 <--> deploymentNameCONTAINER_PORT: "8081" #服务端口 <--> servicesPortNAMESPACE: "$CI_PROJECT_NAME-$CI_PROJECT_ID-$CI_ENVIRONMENT_SLUG" #名称空间ENV_URL: "${ENV_NAME}.${CI_PROJECT_NAMESPACE}.${CI_PROJECT_NAME}.devops.com" #IngressHosts
流水线设置
## 流水线控制
workflow:rules:- if: "$CI_MERGE_REQUEST_ID" #过滤合并请求when: never- if: "$CI_PIPELINE_SOURCE == 'web'" #允许在web页面发布- if: "$CI_COMMIT_REF_NAME =~ /^RELEASE-*/ || $CI_COMMIT_REF_NAME =~ /master/ " #过滤版本分支和主干分支提交代码触发when: never- if: "$CI_COMMIT_BEFORE_SHA == '0000000000000000000000000000000000000000'" #过滤分支创建请求when: never### 默认策略- when: always## 运行阶段
stages:- build- test- parallel01- get_analysis_result- deploy-artifact- deploy-feature- rollout-feature- deploy-uat- rollout-uat- deploy-stag- rollout-stag- deploy-prod- rollout-prodcache:paths:- ${CACHE_DIR}before_script:- export
构建作业配置
################# Jobs Configure #####################
## 构建作业
build:image: ${BUILD_IMAGE}extends: .build## 测试作业
test:image: ${BUILD_IMAGE}extends: .testbefore_script:- ls - ls ${CACHE_DIR}## 代码扫描
code_analysis:stage: parallel01image: ${SONAR_IMAGE}extends: .code_analysis## 获取构建结果
get_analysis_result:image: ${CURL_IMAGE}extends: .get_analysis_resultneeds:- code_analysis## 构建镜像
build_image:image: docker:latestservices:- name: docker:dindstage: parallel01extends: .build-docker## 上传制品
deploy_artifact:image: ${CURL_IMAGE}stage: deploy-artifactextends: .deploy-artifact## 下载制品
#down_artifact:
# image: ${CURL_IMAGE}
# stage: down_artifact
# extends: .down-artifact
发布部署作业配置
发布部署作业配置
#################Deploy Feature Jobs Configure #####################
## feature发布应用
deploy_feature:variables:DEPLOY_FILE: 'deployment.yaml'ENV_NAME: 'feature'stage: deploy-featureimage: ${KUBECTL_IMAGE}extends: .deploy_k8senvironment:on_stop: "rollout_feature"rules:- if: $RUN_DEPLOY_K8S == 'no'when: never- if: $CI_COMMIT_REF_NAME =~ /^RELEASE-*/ || $CI_COMMIT_REF_NAME =~ /master/ || $CI_COMMIT_TAGwhen: never- when: manual## 应用回滚
rollout_feature:variables:DEPLOY_FILE: 'deployment.yaml'ENV_NAME: 'feature'stage: rollout-featureimage: ${KUBECTL_IMAGE}extends: .rollout_k8sneeds:- deploy_featurerules:- if: $RUN_DEPLOY_K8S == 'no'when: never- if: $CI_COMMIT_REF_NAME =~ /^RELEASE-*/ || $CI_COMMIT_REF_NAME =~ /master/ || $CI_COMMIT_TAGwhen: never- when: on_failure#################Deploy UAT Jobs Configure #####################
## UAT
deploy_uat:variables:DEPLOY_FILE: 'config/deployment-uat.yaml'ENV_NAME: 'uat'stage: deploy-uatimage: ${KUBECTL_IMAGE}extends: .deploy_k8senvironment:on_stop: "rollout_uat"rules:- if: $RUN_DEPLOY_K8S == 'no'when: never- if: $CI_COMMIT_REF_NAME =~ /^RELEASE-*/ || $CI_COMMIT_REF_NAME =~ /master/ || $CI_COMMIT_TAGwhen: manual- when: never## UAT应用回滚
rollout_uat:variables:DEPLOY_FILE: 'config/deployment-uat.yaml'ENV_NAME: 'uat'stage: rollout-uatimage: ${KUBECTL_IMAGE}extends: .rollout_k8sneeds:- deploy_uatrules:- if: $RUN_DEPLOY_K8S == 'no'when: never- if: $CI_COMMIT_REF_NAME =~ /^RELEASE-*/ || $CI_COMMIT_REF_NAME =~ /master/ || $CI_COMMIT_TAGwhen: on_failure- when: never#################Deploy STAG Jobs Configure #####################
## STAG
deploy_stag:variables:DEPLOY_FILE: 'config/deployment-stag.yaml'ENV_NAME: 'stag'stage: deploy-stagimage: ${KUBECTL_IMAGE}extends: .deploy_k8senvironment:on_stop: "rollout_stag"needs:- deploy_uatrules:- if: $RUN_DEPLOY_K8S == 'no'when: never- if: $CI_COMMIT_REF_NAME =~ /^RELEASE-*/ || $CI_COMMIT_REF_NAME =~ /master/ || $CI_COMMIT_TAGwhen: manual- when: never## STAG应用回滚
rollout_stag:variables:DEPLOY_FILE: 'config/deployment-stag.yaml'ENV_NAME: 'stag'stage: rollout-stagimage: ${KUBECTL_IMAGE}extends: .rollout_k8sneeds:- deploy_stagrules:- if: $RUN_DEPLOY_K8S == 'no'when: never- if: $CI_COMMIT_REF_NAME =~ /^RELEASE-*/ || $CI_COMMIT_REF_NAME =~ /master/ || $CI_COMMIT_TAGwhen: on_failure- when: never#################Deploy PROD Jobs Configure #####################
## PROD
deploy_prod:variables:DEPLOY_FILE: 'config/deployment-prod.yaml'ENV_NAME: 'prod'stage: deploy-prodimage: ${KUBECTL_IMAGE}extends: .deploy_k8senvironment:on_stop: "rollout_prod"needs:- deploy_stagrules:- if: $RUN_DEPLOY_K8S == 'no'when: never- if: $CI_COMMIT_REF_NAME =~ /^RELEASE-*/ || $CI_COMMIT_REF_NAME =~ /master/ || $CI_COMMIT_TAGwhen: manual- when: never## PROD应用回滚
rollout_prod:variables:DEPLOY_FILE: 'config/deployment-prod.yaml'ENV_NAME: 'prod'stage: rollout-prodimage: ${KUBECTL_IMAGE}extends: .rollout_k8sneeds:- deploy_prodrules:- if: $RUN_DEPLOY_K8S == 'no'when: never- if: $CI_COMMIT_REF_NAME =~ /^RELEASE-*/ || $CI_COMMIT_REF_NAME =~ /master/ || $CI_COMMIT_TAGwhen: on_failure- when: never
JAVA项目交付流水线
导入作业模板
include:- project: 'cidevops/cidevops-newci-service'ref: masterfile: 'templates/default-pipeline.yml'
配置项目参数
variables:## 全局配置GIT_CLONE_PATH: ${CI_BUILDS_DIR}/builds/${CI_PROJECT_NAMESPACE}/${CI_PROJECT_NAME}/${CI_PIPELINE_ID} GIT_CHECKOUT: "false"CACHE_DIR: "target/"## 作业控制RUN_PIPELINE_BUILD: "yes" #是否运行构建 yes/no RUN_PIPELINE_TEST: "yes" #是否运行测试 yes/no RUN_CODE_ANALYSIS: "yes" #是否代码扫描 yes/no RUN_BUILD_IMAGE: "yes" #是否生成镜像 yes/noRUN_DEPLOY_ARTIFACTS: "no" #是否上传制品 yes/noRUN_DEPLOY_K8S: "yes" #是否发布K8S yes/no## 依赖容器镜像BUILD_IMAGE: "maven:3.6.3-jdk-8"CURL_IMAGE: "curlimages/curl:7.70.0"SONAR_IMAGE: "sonarsource/sonar-scanner-cli:latest"KUBECTL_IMAGE: "lucj/kubectl:1.17.2"## 构建测试参数MAVEN_OPTS: "-Dmaven.repo.local=/home/gitlab-runner/ci-build-cache/maven " #maven构建参数BUILD_SHELL: 'mvn clean package -DskipTests --settings=./settings.xml ' #构建命令#GRADLE_OPTS: "" #gradle构建参数## 单元测试参数TEST_SHELL : 'mvn test --settings=./settings.xml ' #测试命令JUNIT_REPORT_PATH: 'target/surefire-reports/TEST-*.xml' #单元测试报告## 代码扫描SONAR_SOURCE_DIR : "src" #项目源码目录SONAR_SERVER_URL: "http://192.168.1.200:30090" #SonarQube服务器信息SONAR_SERVER_LOGIN: "ee2bcb37deeb6dfe3a07fe08fb529559b00c1b7b" #Sonar Token最好在项目中定义。SONAR_SCAN_ARGS: "-Dsonar.sources=${SONAR_SOURCE_DIR} -Dsonar.java.binaries=target/classes -Dsonar.java.test.binaries=target/test-classes -Dsonar.java.surefire.report=target/surefire-reports " #项目扫描参数## 构建镜像CI_REGISTRY: 'registry.cn-beijing.aliyuncs.com' #镜像仓库地址 CI_REGISTRY_USER: 'xxxxxx' #仓库用户信息#CI_REGISTRY_PASSWD: 'xxxxxxxx.' #仓库用户密码IMAGE_NAME: "${CI_REGISTRY}/${CI_PROJECT_PATH}:${CI_COMMIT_REF_NAME}-${CI_COMMIT_SHORT_SHA}" #镜像名称DOCKER_FILE_PATH: "./Dockerfile" #Dockerfile位置## 上传制品库(artifactory)#ARTIFACTORY_URL: "http://192.168.1.200:30082/artifactory" #制品库地址#ARTIFACTORY_NAME: "${CI_PROJECT_NAMESPACE}" #制品库名称#ARTIFACT_PACKAGE: "jar" #制品类型#ARTIFACT_PATH: "target/*.${ARTIFACT_PACKAGE}" #制品位置#TARGET_FILE_PATH: "${CI_PROJECT_NAMESPACE}/${CI_PROJECT_NAME}/${CI_COMMIT_REF_NAME}-${CI_COMMIT_SHORT_SHA}" #目标制品位置(目录结构)#TARGET_ARTIFACT_NAME: "${CI_PROJECT_NAME}-${CI_COMMIT_REF_NAME}-${CI_COMMIT_SHORT_SHA}.${ARTIFACT_PACKAGE}" #目标制品名称## 部署应用k8sAPP_NAME: "$CI_PROJECT_NAME" #应用名称 <-->deploymentNameCONTAINER_PORT: "8081" #服务端口 <--> servicesPortNAMESPACE: "$CI_PROJECT_NAME-$CI_PROJECT_ID-$CI_ENVIRONMENT_SLUG" #名称空间ENV_URL: "${ENV_NAME}.${CI_PROJECT_NAMESPACE}.${CI_PROJECT_NAME}.devops.com" #IngressHosts
指定CI文件
运行流水线测试
docker镜像仓库
部署环境演示
Kubernetes集群中应用状态
模板案例
variables:REPOSITORY: "xxxx/xxxxxx"
stages:- deploybuild:stage: deployonly:- masterscript:- docker build -t $REPOSITORY:prod .- docker tag $REPOSITORY:prod "私有镜像库地址"/$REPOSITORY:prod- docker push "私有镜像库地址"/$REPOSITORY:prodtags:- labletest:stage: deployonly:- testscript:- docker build -t $REPOSITORY:testing .- docker tag $REPOSITORY:testing "私有镜像库地址"/$REPOSITORY:testing- docker push "私有镜像库地址"/$REPOSITORY:testingtags:- labledev:stage: deployonly:- devscript:- docker build -t $REPOSITORY:dev .- docker tag $REPOSITORY:dev "私有镜像库地址"/$REPOSITORY:dev- docker push "私有镜像库地址"/$REPOSITORY:devtags:- lable
相关文章:

DevOps系列文章 之GitLabCI模板库的流水线
目录结构,jobs目录用于存放作业模板。templates目录用于存放流水线模板。这次使用default-pipeline.yml作为所有作业的基础模板。 作业模板 作业分为Build、test、codeanalysis、artifactory、deploy部分,在每个作业中配置了rules功能开关&…...
spring扩展点ApplicationContextAware解释
ApplicationContextAware是Spring框架中的一个扩展接口,用于获取和操作应用程序上下文(ApplicationContext)。通过实现ApplicationContextAware接口,可以在Bean中获取对应用程序上下文的引用,并进行进一步的操作。 具…...

力扣热门100题之最大子数组和【中等】【动态规划】
题目描述 给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。 子数组 是数组中的一个连续部分。 示例 1: 输入:nums [-2,1,-3,4,-1,2,1,-5,4] 输出&a…...

导出为PDF加封面且分页处理dom元素分割
文章目录 正常展示页面导出后效果代码 正常展示页面 导出后效果 代码 组件内 <template><div><div><div class"content" id"content" style"padding: 0px 20px"><div class"item"><divstyle"…...

【C++入门】浅谈类、对象和 this 指针
文章目录 一、前言二、类1. 基本概念2. 类的封装3. 使用习惯成员函数定义习惯成员变量命名习惯 三、对象1. 基本概念2. 类对象的存储规则 四、this 指针1. 基本概念2. 注意事项3. 经典习题4. 常见面试题 一、前言 在 C 语言中,我们用结构体来描述一个事物的多种属性…...

【Linux命令200例】indent对C语言代码进行缩进和格式化
🏆作者简介,黑夜开发者,全栈领域新星创作者✌,2023年6月csdn上海赛道top4。 🏆本文已收录于专栏:Linux命令大全。 🏆本专栏我们会通过具体的系统的命令讲解加上鲜活的实操案例对各个命令进行深入…...

Hive 调优集锦(1)
一、前言 1.1 概念 Hive 依赖于 HDFS 存储数据,Hive 将 HQL 转换成 MapReduce 执行,所以说 Hive 是基于Hadoop 的一个数据仓库工具,实质就是一款基于 HDFS 的 MapReduce 计算框架,对存储在HDFS 中的数据进行分析和管理。 1.2 架…...

【C++详解】——智能指针
目录 为什么需要智能指针 抛异常引发内存泄漏 内存泄漏 什么是内存泄漏,内存泄漏的危害 内存泄漏分类 检测内存泄漏常用工具 如何避免内存泄漏 智能指针的使用及原理 RAII 智能指针的原理 各类智能指针介绍 auto_ptr unique_ptr shared_ptr weak_ptr …...

Jmeter接口/性能测试,Jmeter使用教程(超细整理)
目录:导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结(尾部小惊喜) 前言 1、线程组 线程组…...
59,综合案例-演讲比赛流程管理系统
演讲比赛流程管理系统 59.1案例描述59.1.1比赛规则59.1.2程序功能 59.2创建管理类59.3菜单功能59.3.1添加成员函数59.3.2菜单功能实现 59.4退出功能59.4.1提供功能接口59.4.2实现退出功能 59.5演讲比赛功能59.5.1创建选手类59.5.2比赛59.5.2.1成员属性添加59.5.2.2初始化属性59…...

前端JS 展示上传图片缩略图(本地图片读取)
需求: 点击上传图片按钮,选择图片以后,不请求后端接口,直接将图片展示在缩略图中。 解决方案: 使用 FileReader 和 FileReader 中的 readAsDataURL 方法。 第一步 从input[type“file”] (上传文件标签) 里面拿到fil…...

Vue中$route和$router的区别
$router:用来操作路由,$route:用来获取路由信息 $router其实就是VueRouer的实例,对象包括了vue-router使用的实例方法,还有实例属性,我们可以理解为$router有一个设置的含义,比如设置当前的跳转…...

基于多任务学习卷积神经网络的皮肤损伤联合分割与分类
文章目录 Joint segmentation and classification of skin lesions via a multi-task learning convolutional neural network摘要本文方法实验结果 Joint segmentation and classification of skin lesions via a multi-task learning convolutional neural network 摘要 在…...

串口环形缓冲区
文章目录 一、串口环形缓冲区概念二、STC12例程(1)环形串口缓冲区结构体(2)串口环形缓冲区存和取数据(3)完整工程demo 一、串口环形缓冲区概念 串口环形缓冲区应用于嵌入式、物联网开发中处理接收串口数据…...

【腾讯云 Cloud Studio 实战训练营】基于Cloud Studio完成简易通讯录
目录 🔆Cloud Studio 简介 操作步骤 1.登录 2.创建工作空间 3.初始界面 4.开发空间 5.保存自定义模板 🔆简易通讯录 1.实验要求 2.操作环境 3.源代码介绍 3.1 定义通讯录类 3.2 定义通讯录列表 3.3 添加联系人功能 3.4 修改联系人 3.5 …...

【技术积累】Vue.js中的核心知识
Vue的生命周期 Vue中的生命周期是指组件从创建到销毁的整个过程中,会触发一系列的钩子函数 Vue2中的生命周期 Vue2中的生命周期钩子函数是在组件的不同阶段执行的特定函数。这些钩子函数允许开发者在组件的不同生命周期阶段执行自定义的逻辑。 Vue2中的生命周期钩…...
flutter开发实战-显示本地图片网络图片及缓存目录图片
flutter开发实战-显示本地图片网络图片及缓存目录图片 在最近开发中碰到了需要显示缓存目录图片,这里顺便整理一下,显示本地图片、网络图片、缓存目录图片的方法。 一、工程本地图片显示 1 在项目根目录下创建名为 images文件夹,也可以将i…...
面对未来的算法备案法规:企业需要做哪些准备?
在信息时代,算法已经成为我们生活的一部分,涵盖了诸如搜索引擎、社交媒体、电子商务、广告投放等各个方面。然而,随着算法的广泛应用,其带来的问题也日益凸显。这引发了全球范围内的关注,未来的算法备案法规正在酝酿之…...

iptables的备份和还原
iptables的备份和还原 1、写在命令行当中的都是临时设置 2、把规则配置写在服务的文件当中,形成永久有效 备份:把iptables里面所有的配置都保存在/opt/ky30.bak中 iptables-save > /opt/ky30.bak 例: 默认配置文件在/etc/sysconfig/ip…...

easyUI框架学习
文章目录 一、前言二、引入使用easyUI 三、用法3.1 Dialog(对话框窗口)3.1.1 示例13.1.2 示例2 3.2 Layout(布局)3.2.1 示例1——通过标签创建布局3.2.2 示例2—— 创建嵌套布局 3.3 DateBox(日期输入框)3.…...
golang循环变量捕获问题
在 Go 语言中,当在循环中启动协程(goroutine)时,如果在协程闭包中直接引用循环变量,可能会遇到一个常见的陷阱 - 循环变量捕获问题。让我详细解释一下: 问题背景 看这个代码片段: fo…...

抖音增长新引擎:品融电商,一站式全案代运营领跑者
抖音增长新引擎:品融电商,一站式全案代运营领跑者 在抖音这个日活超7亿的流量汪洋中,品牌如何破浪前行?自建团队成本高、效果难控;碎片化运营又难成合力——这正是许多企业面临的增长困局。品融电商以「抖音全案代运营…...
电脑插入多块移动硬盘后经常出现卡顿和蓝屏
当电脑在插入多块移动硬盘后频繁出现卡顿和蓝屏问题时,可能涉及硬件资源冲突、驱动兼容性、供电不足或系统设置等多方面原因。以下是逐步排查和解决方案: 1. 检查电源供电问题 问题原因:多块移动硬盘同时运行可能导致USB接口供电不足&#x…...
【论文笔记】若干矿井粉尘检测算法概述
总的来说,传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度,通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...

Python爬虫(一):爬虫伪装
一、网站防爬机制概述 在当今互联网环境中,具有一定规模或盈利性质的网站几乎都实施了各种防爬措施。这些措施主要分为两大类: 身份验证机制:直接将未经授权的爬虫阻挡在外反爬技术体系:通过各种技术手段增加爬虫获取数据的难度…...

零基础设计模式——行为型模式 - 责任链模式
第四部分:行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习!行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想:使多个对象都有机会处…...
LeetCode - 199. 二叉树的右视图
题目 199. 二叉树的右视图 - 力扣(LeetCode) 思路 右视图是指从树的右侧看,对于每一层,只能看到该层最右边的节点。实现思路是: 使用深度优先搜索(DFS)按照"根-右-左"的顺序遍历树记录每个节点的深度对于…...

中医有效性探讨
文章目录 西医是如何发展到以生物化学为药理基础的现代医学?传统医学奠基期(远古 - 17 世纪)近代医学转型期(17 世纪 - 19 世纪末)现代医学成熟期(20世纪至今) 中医的源远流长和一脉相承远古至…...

C++:多态机制详解
目录 一. 多态的概念 1.静态多态(编译时多态) 二.动态多态的定义及实现 1.多态的构成条件 2.虚函数 3.虚函数的重写/覆盖 4.虚函数重写的一些其他问题 1).协变 2).析构函数的重写 5.override 和 final关键字 1&#…...
SQL慢可能是触发了ring buffer
简介 最近在进行 postgresql 性能排查的时候,发现 PG 在某一个时间并行执行的 SQL 变得特别慢。最后通过监控监观察到并行发起得时间 buffers_alloc 就急速上升,且低水位伴随在整个慢 SQL,一直是 buferIO 的等待事件,此时也没有其他会话的争抢。SQL 虽然不是高效 SQL ,但…...