当前位置: 首页 > news >正文

k8s的ci/cd实践之旅

书接上回k8s集群搭建完毕,来使用它强大的扩缩容能力帮我们进行应用的持续集成和持续部署,整体的机器规划如下:

1.192.168.8.156 搭建gitlab私服 

docker pull gitlab/gitlab-ce:latest docker run --detach --hostname 192.168.8.156 --publish 443:443 --publish 80:80 --publish 2022:22 --name gitlab --restart always --volume /srv/gitlab/config:/etc/gitlab --volume /srv/gitlab/logs:/var/log/gitlab --volume /srv/gitlab/data:/var/opt/gitlab gitlab/gitlab-ce:latest

root密码查看:

 docker exec -it gitlab grep "Password": /etc/gitlab/initial_root_password


新建用户dxy并用管理员root账号进行审批

结果如图并创建项目git,一个最简单的springboot项目

2.192.168.8.157 搭建docker私服 habor

   首先,需要在服务器上安装 docker 和 docker-compose,执行如下命令。

   yum install docker docker-compose

    接着下载 harbor 软件包

 wget https://storage.googleapis.com/harbor-releases/harbor-offline-installer-v1.5.3.tgz

   解压并安装  

    

 tar -zxvf harbor-offline-installer-v1.5.3.tgz -C /opt/software/habor/

进入/opt/software/habor/harbor目录下,修改文件 harbor.cfg,修改如下字段

hostname = 192.168.8.157  # 修改 IP 地址为本机 IP

执行如下命令,安装 harbor

./prepare

./install.sh

在浏览器输入 http://192.168.8.157/harbor/sign-in,进入 harbor UI 界面,如下所示。

默认用户名和密码如下

用户名:admin密码:Harbor12345密码在 /opt/harbor/harbor.cfg 中配置,默认是 Harbor12345

修改docker配置文件/etc/docker/daemon.json内容如下

{ "insecure-registries": ["192.168.8.157"],"registry-mirrors": ["https://z0o173bp.mirror.aliyuncs.com"]
}

重启docker

 systemctl daemon-reload

 systemctl docker restart

依据提示进行镜像的推送

docker tag docker.io/mysql:5.7 192.168.8.157/library/mysql:5.0

docker push 192.168.8.157/library/mysql:5.0

3.192.168.8.158 搭建Jenkins部署服务器

 下载Jenkins并配置好java环境

  wget http://mirrors.jenkins.io/war-stable/latest/jenkins.war

 启动jenkis

nohup java -jar jenkins.war --httpPort=8080 & tail -f nohup.out 

启动后的解锁密码如图忘记可以用如下命令查看

cat /root/.jenkins/secrets/initialAdminPassword

安装推荐的插件并配置好maven、git和jdk如下:

   

按照完成后可以新建一个流水线测试一下是否可以正常拉取代码和打包构建(Jenkins上需要配置公钥并在gitlab上添加ssh授权key)

4.将Jenkins构建后的包打成镜像并上传到镜像仓库

在Jenkins的工作目录中新建scripte目录,并加一个把构建后的jar包打包成镜像的脚本文件命名为springboot-demo-build-image.sh如下:

mkdir /root/.jenkins/workspace/scripts/vi /root/.jenkins/workspace/scripts/springboot-demo-build-image.shchmod +x /root/.jenkins/workspace/scripts/*.sh
# 进入到springboot-demo目录
cd ../springboot-demo# 编写Dockerfile文件cat <<EOF > Dockerfile
FROM openjdk:8-jre-alpine
COPY target/springboot-demo-0.0.1-SNAPSHOT.jar /springboot-demo.jar
ENTRYPOINT ["java","-jar","/springboot-demo.jar"]
EOFecho "Dockerfile created successfully!"# 基于指定目录下的Dockerfile构建镜像
docker build -t 192.168.8.157/library/springboot-demo:v1.0 .# push镜像,这边需要habor镜像仓库登录,在jenkins服务器上登录
docker push 192.168.8.157/library/springboot-demo:v1.0

增加流水线的步骤如下:

  stage('Build Image') { 
      sh "/root/.jenkins/workspace/scripts/springboot-demo-build-image.sh"
   }

重新构建可以看的流水线上已经把镜像推送到harbor镜像仓库里了

5.k8s从镜像仓库中拉取镜像并部署

修改Jenkins步骤增加如下在master节点中操作的步骤

def remote = [:]
  remote.name = 'k8s master'
  remote.host = '192.168.8.153'
  remote.user = 'root'
  remote.password = 'dxy666,,'
  remote.allowAnyHosts = true
  stage('Remote SSH') {
    writeFile file: '/opt/project/k8s-deploy-springboot-demo.sh', text: 'ls -lrt'
    sshScript remote: remote, script: "/opt/project/k8s-deploy-springboot-demo.sh"
 
  }

在master节点的工作目录/opt/project下创建springboot-demo.yaml用于将镜像拉取并在指定机器上执行

# 以Deployment部署Pod
apiVersion: apps/v1
kind: Deployment
metadata:name: springboot-demo
spec:selector:matchLabels:app: springboot-demoreplicas: 1template:metadata:labels:app: springboot-demospec:containers:- name: springboot-demoimage: 192.168.8.157/library/springboot-demo:v1.0ports:- containerPort: 8080
---
# 创建Pod的Service
apiVersion: v1
kind: Service
metadata:name: springboot-demo
spec:ports:- port: 80protocol: TCPtargetPort: 8080selector:app: springboot-demo
---
# 创建Ingress,定义访问规则
apiVersion: extensions/v1beta1
kind: Ingress
metadata:name: springboot-demo
spec:rules:- host: springboot.k8s.comhttp:paths:- path: /backend:serviceName: springboot-demoservicePort: 80

创建k8s的inress网络yaml文件指定在w1上

# 确保nginx-controller运行到w1节点上
kubectl label node w1 name=ingress   
apiVersion: v1
kind: Namespace
metadata:name: ingress-nginxlabels:app.kubernetes.io/name: ingress-nginxapp.kubernetes.io/part-of: ingress-nginx---kind: ConfigMap
apiVersion: v1
metadata:name: nginx-configurationnamespace: ingress-nginxlabels:app.kubernetes.io/name: ingress-nginxapp.kubernetes.io/part-of: ingress-nginx---
kind: ConfigMap
apiVersion: v1
metadata:name: tcp-servicesnamespace: ingress-nginxlabels:app.kubernetes.io/name: ingress-nginxapp.kubernetes.io/part-of: ingress-nginx---
kind: ConfigMap
apiVersion: v1
metadata:name: udp-servicesnamespace: ingress-nginxlabels:app.kubernetes.io/name: ingress-nginxapp.kubernetes.io/part-of: ingress-nginx---
apiVersion: v1
kind: ServiceAccount
metadata:name: nginx-ingress-serviceaccountnamespace: ingress-nginxlabels:app.kubernetes.io/name: ingress-nginxapp.kubernetes.io/part-of: ingress-nginx---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:name: nginx-ingress-clusterrolelabels:app.kubernetes.io/name: ingress-nginxapp.kubernetes.io/part-of: ingress-nginx
rules:- apiGroups:- ""resources:- configmaps- endpoints- nodes- pods- secretsverbs:- list- watch- apiGroups:- ""resources:- nodesverbs:- get- apiGroups:- ""resources:- servicesverbs:- get- list- watch- apiGroups:- ""resources:- eventsverbs:- create- patch- apiGroups:- "extensions"- "networking.k8s.io"resources:- ingressesverbs:- get- list- watch- apiGroups:- "extensions"- "networking.k8s.io"resources:- ingresses/statusverbs:- update---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: Role
metadata:name: nginx-ingress-rolenamespace: ingress-nginxlabels:app.kubernetes.io/name: ingress-nginxapp.kubernetes.io/part-of: ingress-nginx
rules:- apiGroups:- ""resources:- configmaps- pods- secrets- namespacesverbs:- get- apiGroups:- ""resources:- configmapsresourceNames:# Defaults to "<election-id>-<ingress-class>"# Here: "<ingress-controller-leader>-<nginx>"# This has to be adapted if you change either parameter# when launching the nginx-ingress-controller.- "ingress-controller-leader-nginx"verbs:- get- update- apiGroups:- ""resources:- configmapsverbs:- create- apiGroups:- ""resources:- endpointsverbs:- get---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: RoleBinding
metadata:name: nginx-ingress-role-nisa-bindingnamespace: ingress-nginxlabels:app.kubernetes.io/name: ingress-nginxapp.kubernetes.io/part-of: ingress-nginx
roleRef:apiGroup: rbac.authorization.k8s.iokind: Rolename: nginx-ingress-role
subjects:- kind: ServiceAccountname: nginx-ingress-serviceaccountnamespace: ingress-nginx---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:name: nginx-ingress-clusterrole-nisa-bindinglabels:app.kubernetes.io/name: ingress-nginxapp.kubernetes.io/part-of: ingress-nginx
roleRef:apiGroup: rbac.authorization.k8s.iokind: ClusterRolename: nginx-ingress-clusterrole
subjects:- kind: ServiceAccountname: nginx-ingress-serviceaccountnamespace: ingress-nginx---apiVersion: apps/v1
kind: Deployment
metadata:name: nginx-ingress-controllernamespace: ingress-nginxlabels:app.kubernetes.io/name: ingress-nginxapp.kubernetes.io/part-of: ingress-nginx
spec:replicas: 1selector:matchLabels:app.kubernetes.io/name: ingress-nginxapp.kubernetes.io/part-of: ingress-nginxtemplate:metadata:labels:app.kubernetes.io/name: ingress-nginxapp.kubernetes.io/part-of: ingress-nginxannotations:prometheus.io/port: "10254"prometheus.io/scrape: "true"spec:# wait up to five minutes for the drain of connectionsterminationGracePeriodSeconds: 300serviceAccountName: nginx-ingress-serviceaccounthostNetwork: truenodeSelector:name: ingresskubernetes.io/os: linuxcontainers:- name: nginx-ingress-controllerimage: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.26.1args:- /nginx-ingress-controller- --configmap=$(POD_NAMESPACE)/nginx-configuration- --tcp-services-configmap=$(POD_NAMESPACE)/tcp-services- --udp-services-configmap=$(POD_NAMESPACE)/udp-services- --publish-service=$(POD_NAMESPACE)/ingress-nginx- --annotations-prefix=nginx.ingress.kubernetes.iosecurityContext:allowPrivilegeEscalation: truecapabilities:drop:- ALLadd:- NET_BIND_SERVICE# www-data -> 33runAsUser: 33env:- name: POD_NAMEvalueFrom:fieldRef:fieldPath: metadata.name- name: POD_NAMESPACEvalueFrom:fieldRef:fieldPath: metadata.namespaceports:- name: httpcontainerPort: 80- name: httpscontainerPort: 443livenessProbe:failureThreshold: 3httpGet:path: /healthzport: 10254scheme: HTTPinitialDelaySeconds: 10periodSeconds: 10successThreshold: 1timeoutSeconds: 10readinessProbe:failureThreshold: 3httpGet:path: /healthzport: 10254scheme: HTTPperiodSeconds: 10successThreshold: 1timeoutSeconds: 10lifecycle:preStop:exec:command:- /wait-shutdown---

kubectl apply -f mandatory.yaml  

查看对应ingress是否ok  

 kubectl get ingress

修改host文件中对应域名未指定service对应ip即可

10.104.129.15 springboot.k8s.com

6.访问对应地址查看是否使用了镜像构建

先手动执行一下部署yaml看下是否有格式的问题如下:

再次提交从0000->改成1111

7.遗留问题

  gitlab hook无法触发Jenkins自动构建报错如下:

  尝试修改-Djava.awt.headless=true -Dhudson.security.csrf.GlobalCrumbIssuerConfiguration.DISABLE_CSRF_PROTECTION=true  后仍旧失败可能是这个版本的Jenkins没有关闭跨站点防护功能,主题流程基本走通,后续有时间在换个版本看看。

相关文章:

k8s的ci/cd实践之旅

书接上回k8s集群搭建完毕&#xff0c;来使用它强大的扩缩容能力帮我们进行应用的持续集成和持续部署&#xff0c;整体的机器规划如下&#xff1a; 1.192.168.8.156 搭建gitlab私服 docker pull gitlab/gitlab-ce:latest docker run --detach --hostname 192.168.8.156 --publ…...

笔记96:前馈控制 + 航向误差

1. 回顾 对于一个 系统而言&#xff0c;结构可以画作&#xff1a; 如果采用 这样的控制策略&#xff0c;结构可以画作&#xff1a;&#xff08;这就是LQR控制&#xff09; 使用LQR控制器&#xff0c;可以通过公式 和 构建一个完美的负反馈系统&#xff1b; a a 但是有上…...

延时任务工具类

自定义工具类 package com.sxfoundation.task;import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.task.TaskRejectedException; import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; import org.spri…...

springboot下载grpc编译文件,报错缺少protoc-gen-grpc-java:1.34.1:exe不存在

报错如图所示 [ERROR] Then, install it using the command: [ERROR] mvn install:install-file -DgroupIdio.grpc -DartifactIdprotoc-gen-grpc-java -Dversion1.34.1 -Dclassifierwindows-x86_64 -Dpackagingexe -Dfile/path/to/file [ERROR] [ERROR] Alternatively, if yo…...

【面试干货】 非关系型数据库(NoSQL)与 关系型数据库(RDBMS)的比较

【面试干货】 非关系型数据库&#xff08;NoSQL&#xff09;与 关系型数据库&#xff08;RDBMS&#xff09;的比较 一、引言二、非关系型数据库&#xff08;NoSQL&#xff09;2.1 优势 三、关系型数据库&#xff08;RDBMS&#xff09;3.1 优势 四、结论 &#x1f496;The Begin…...

JAVA学习-练习试用Java实现“简化路径”

问题&#xff1a; 给定一个字符串 path &#xff0c;表示指向某一文件或目录的 Unix 风格 绝对路径 &#xff08;以 / 开头&#xff09;&#xff0c;请将其转化为更加简洁的规范路径。 在 Unix 风格的文件系统中&#xff0c;一个点&#xff08;.&#xff09;表示当前目录本身…...

STM32——ADC篇(ADC的使用)

一、ADC的介绍 1.1什么是ADC ADC&#xff08;Analogto-Digital Converter&#xff09;模拟数字转换器&#xff0c;是将模拟信号转换成数字信号的一种外设。比如某一个电阻两端的是一个模拟信号&#xff0c;单片机无法直接采集&#xff0c;此时需要ADC先将短租两端的电…...

(文章复现)基于主从博弈的售电商多元零售套餐设计与多级市场购电策略

参考文献&#xff1a; [1]潘虹锦,高红均,杨艳红,等.基于主从博弈的售电商多元零售套餐设计与多级市场购电策略[J].中国电机工程学报,2022,42(13):4785-4800. 1.摘要 随着电力市场改革的发展&#xff0c;如何制定吸引用户选择的多类型零售套餐成为提升售电商利润的研究重点。为…...

深度评价GPT-4o:探索人工智能的新里程碑

在人工智能领域&#xff0c;OpenAI的GPT系列自推出以来就备受瞩目。GPT-4o作为该系列的最新版本&#xff0c;无疑是迄今为止最为强大的一代。它不仅在技术性能上有了质的飞跃&#xff0c;而且在应用的广泛性和深度上都展现出了惊人的潜力。本文将从版本对比、技术能力、使用体验…...

Linux命令篇(六):vi/vim专项

&#x1f49d;&#x1f49d;&#x1f49d;首先&#xff0c;欢迎各位来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里不仅可以有所收获&#xff0c;同时也能感受到一份轻松欢乐的氛围&#xff0c;祝您生活愉快&#xff01; 文章目录 一、什么是vim二…...

Java 还能不能继续搞了?

金三银四招聘季已落幕&#xff0c;虽说行情不是很乐观&#xff0c;但真正的强者从不抱怨。 在此期间&#xff0c;我收到众多小伙伴的宝贵反馈&#xff0c;整理出132道面试题&#xff0c;从基础到高级&#xff0c;有八股文&#xff0c;也有对某个知识点的深度解析。包括以下几部…...

【日记】遇到了一个很奇怪的大爷(845 字)

正文 花了昨天和今天两天时间&#xff0c;把数据转移完了。这块 2T 的硬盘可以光荣退休了。目前是没什么存储焦虑了。 农发行净开发一些垃圾系统。今天没什么业务&#xff0c;但跟 ActiveX 斗智斗勇了一整天&#xff0c;最后实在搞不过 IE 浏览器。我也懒得管了&#xff0c;又不…...

Python 机器学习 基础 之 处理文本数据 【处理文本数据/用字符串表示数据类型/将文本数据表示为词袋】的简单说明

Python 机器学习 基础 之 处理文本数据 【处理文本数据/用字符串表示数据类型/将文本数据表示为词袋】的简单说明 目录 Python 机器学习 基础 之 处理文本数据 【处理文本数据/用字符串表示数据类型/将文本数据表示为词袋】的简单说明 一、简单介绍 二、处理文本数据 三、用…...

GAT1399协议分析(10)--视频定义及解析

一、官方定义 二、字段解析 VideoID 类型BasicObjectID 解析参考GAT1399协议分析(8)--ImageInfo字段详解-CSDN博客 InfoKind 采集类型...

【C语言】学生管理系统:完整模拟与实现

&#x1f308;个人主页&#xff1a;是店小二呀 &#x1f308;C语言笔记专栏&#xff1a;C语言笔记 &#x1f308;C笔记专栏&#xff1a; C笔记 &#x1f308;喜欢的诗句:无人扶我青云志 我自踏雪至山巅 &#x1f525;引言 本篇文章为修改了在校期间实训报告&#xff0c;使用C…...

pypi 发布自己的包

注册pypi个人用户 网址&#xff1a;https://pypi.org 目录结构dingtalk_utils 必须-pkgs- __init__.py .gitignore LICENSE 必须 README.md 必须 requirements.txt setup.py 必须安装依赖 pip install setuptools wheel安装上传工具 pip install twinesetup.py i…...

关闭windows11磁盘地址栏上的历史记录

关闭windows11的磁盘地址栏上的历史记录 windows11打开磁盘后访问某一个磁盘路径后会记录这个磁盘路径&#xff0c;而且有时候会卡住这个地址栏&#xff08;关都关不掉&#xff09;&#xff0c;非常麻烦。 如下图所示&#xff1a; 关闭地址栏历史记录 按下windows键打开开…...

DDS自动化测试落地方案 | 怿星科技携最新技术亮相是德科技年度盛会

5月28日&#xff0c;怿星科技作为是德科技的重要合作伙伴亮相Keysight World Tech Day 2024。在此次科技盛会上&#xff0c;怿星科技不仅展示了领先的DDS自动化测试解决方案等前沿技术&#xff0c;还分享了在“周期短、任务重”的情况下&#xff0c;如何做好软件开发和测试验证…...

新品!和芯星通全系统全频高精度板卡UB9A0首发

6月6日&#xff0c;和芯星通发布了UB9A0全系统全频高精度GNSS板卡&#xff0c;主要应用于CORS站、便携基站、GNSS全球监测跟踪站等。延续了上一代产品高质量原始观测量的特点&#xff0c;UB9A0在性能和稳定性方面均表现出众。 UB9A0基于射频基带及高精度算法一体化的GNSS SoC芯…...

Cognita RAG:模块化、易用与可扩展的开源框架

Cognita RAG是一个开源框架&#xff0c;它通过模块化设计、用户友好的界面和可扩展性&#xff0c;简化了将领域特定知识整合到通用预训练语言模型中的过程。本文介绍了Cognita的特点、优势、应用场景以及如何帮助开发者构建适合生产环境的RAG应用程序。 文章目录 Cognita RAG介…...

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…...

在鸿蒙HarmonyOS 5中实现抖音风格的点赞功能

下面我将详细介绍如何使用HarmonyOS SDK在HarmonyOS 5中实现类似抖音的点赞功能&#xff0c;包括动画效果、数据同步和交互优化。 1. 基础点赞功能实现 1.1 创建数据模型 // VideoModel.ets export class VideoModel {id: string "";title: string ""…...

页面渲染流程与性能优化

页面渲染流程与性能优化详解&#xff08;完整版&#xff09; 一、现代浏览器渲染流程&#xff08;详细说明&#xff09; 1. 构建DOM树 浏览器接收到HTML文档后&#xff0c;会逐步解析并构建DOM&#xff08;Document Object Model&#xff09;树。具体过程如下&#xff1a; (…...

苍穹外卖--缓存菜品

1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得&#xff0c;如果用户端访问量比较大&#xff0c;数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据&#xff0c;减少数据库查询操作。 缓存逻辑分析&#xff1a; ①每个分类下的菜品保持一份缓存数据…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个生活电费的缴纳和查询小程序

一、项目初始化与配置 1. 创建项目 ohpm init harmony/utility-payment-app 2. 配置权限 // module.json5 {"requestPermissions": [{"name": "ohos.permission.INTERNET"},{"name": "ohos.permission.GET_NETWORK_INFO"…...

QT: `long long` 类型转换为 `QString` 2025.6.5

在 Qt 中&#xff0c;将 long long 类型转换为 QString 可以通过以下两种常用方法实现&#xff1a; 方法 1&#xff1a;使用 QString::number() 直接调用 QString 的静态方法 number()&#xff0c;将数值转换为字符串&#xff1a; long long value 1234567890123456789LL; …...

智能仓储的未来:自动化、AI与数据分析如何重塑物流中心

当仓库学会“思考”&#xff0c;物流的终极形态正在诞生 想象这样的场景&#xff1a; 凌晨3点&#xff0c;某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径&#xff1b;AI视觉系统在0.1秒内扫描包裹信息&#xff1b;数字孪生平台正模拟次日峰值流量压力…...

基于 TAPD 进行项目管理

起因 自己写了个小工具&#xff0c;仓库用的Github。之前在用markdown进行需求管理&#xff0c;现在随着功能的增加&#xff0c;感觉有点难以管理了&#xff0c;所以用TAPD这个工具进行需求、Bug管理。 操作流程 注册 TAPD&#xff0c;需要提供一个企业名新建一个项目&#…...

【JavaSE】多线程基础学习笔记

多线程基础 -线程相关概念 程序&#xff08;Program&#xff09; 是为完成特定任务、用某种语言编写的一组指令的集合简单的说:就是我们写的代码 进程 进程是指运行中的程序&#xff0c;比如我们使用QQ&#xff0c;就启动了一个进程&#xff0c;操作系统就会为该进程分配内存…...

淘宝扭蛋机小程序系统开发:打造互动性强的购物平台

淘宝扭蛋机小程序系统的开发&#xff0c;旨在打造一个互动性强的购物平台&#xff0c;让用户在购物的同时&#xff0c;能够享受到更多的乐趣和惊喜。 淘宝扭蛋机小程序系统拥有丰富的互动功能。用户可以通过虚拟摇杆操作扭蛋机&#xff0c;实现旋转、抽拉等动作&#xff0c;增…...