hello云胜

技术与生活

0%

jenkins流水线在某个节点上执行失败

故障背景

使用的是kubesphere内置的jenkins

今天出现一个故障,在在某一台机器上流水线mvn打包执行失败,将这台机器禁止调度。流水线在其他节点正常。

image-20230913110815903

排查过程

根据项目基本可以确定是某一台机器的环境有问题。

jenkins的流水线在实行过程中,是拉起新的pod作为jenkins-slave进行流水线工作。所以一旦流水线失败,pod会被删除。导致我们无法进入容器内部进行排查。

我们可以在jenkinsfile中,加上sleep,停住容器,以便我们进行排查。

1
2
3
4
5
container('maven') {
sh 'sleep 9999999'
sh 'mvn clean package -Dmaven.test.skip=true -Ptest'
}

注意,pod里会有两个container

1
2
[root@t-paas-k8s-0-master-0 ~]# kubectl -n kubesphere-devops-system get pod maven-pbxgv -o jsonpath={.spec.containers[*].name}
jnlp maven

应该进入maven容器,这是真正执行mvn命令的容器。

进去执行mvn,果然也是一样的报错。

猜测是不是下载的依赖包有问题。

删除了容器里的依赖,本地仓库位置如果没有改,默认是~/.m2下

重新执行mvn编译。

mvn重新下载依赖,果然好了。

那就是说明确实是之前下载的依赖包损坏的问题。

解决方案

原因是第一次下载依赖有错误,后续不会再重复下载,导致编译出错。

所以想出三种解决办法,都可以解决。

1,修改JenkinsFile,sleep住然后进入maven容器,删除依赖。重新执行流水线

2,使用maven强制更新依赖的命令

1
mvn dependency:purge-local-repository

3,k8s的jenkins slave会把依赖下载到宿主机,启动的每个slave容器都使用这一份依赖,不会每次都重新下载。

路径是 /var/lib/docker/volumes/jenkins_maven_cache/_data/

所以,也可以直接把这个路径下的有问题的依赖删了,让maven重新下

和在容器里删除效果一样,但是操作更方便。

Jenkins官方文档执行的几个错误解决

开始做一些devops工程方面的工作,那必然第一个接触的就是Jenkins。

但是Jenkins的文档真是太坑了。

为了跑通一个官方例子,今天一下午全耗在这上了。索性最终是踩坑完毕。

下面总结下我遇到的几个坑。大家可及时跳过。

我实验的例子是官方的使用Maven构建Java应用程序

先说一下我部署Jenkins的方法。

1
2
3
4
5
6
7
8
9
10
11
docker run \
-u root \
-d \
-p 8080:8080 \
-p 50000:50000 \
-v jenkins-data:/var/jenkins_home \
-v /etc/localtime:/etc/localtime:ro \
-v /var/run/docker.sock:/var/run/docker.sock \
--name jenkins-blueocean \
--restart=always \
jenkinsci/blueocean

-v /etc/localtime:/etc/localtime:ro 作用是同步主机时区

-v /var/run/docker.sock:/var/run/docker.sock

表示Docker守护程序通过其监听的基于Unix的套接字。 该映射允许 jenkinsci/blueocean 容器与Docker守护进程通信, 如果 jenkinsci/blueocean 容器需要实例化 其他Docker容器,则该守护进程是必需的。

或者不是通过volume,也可以直接挂载到服务器的目录上,这样查看文件比较方便

1
-v $HOME/jenkins_home:/var/jenkins_home

1,本地构建问题

官方的例子是,将源码仓库下载到jenkins所在的服务器。

只要将git仓库下载到jenkin本地的路径下。jenkins可以识别这是一个git仓库进而构建它。

注意:使用docker部署的,所以填写的路径是jenkins容器里的路径。

我之前用-v $HOME/jenkins_home:/var/jenkins_home将/var/jenkins_home目录挂载出来了。

image-20220706143552593

不用尝试了,会报错

1
Checkout of Git remote '/var/jenkins_home/GitHub/simple-java-maven-app' aborted because it references a local directory, which may be insecure. You can allow local checkouts anyway by setting the system property 'hudson.plugins.git.GitSCM.ALLOW_LOCAL_CHECKOUT' to true.

查了下,这个变量可以配置,具体怎么做我还没查到。

但是不想解决了,没什么意义。因为我们以后也不会用本地构建。都是从远程仓库拉代码的。

2,maven版本问题

案例中给的Jenkinsfile使用的镜像版本是maven:3-alpine

1
2
3
4
5
6
agent {
docker {
image 'maven:3-alpine'
args '-v /root/.m2:/root/.m2'
}
}

但是在他的代码里

1
2
3
4
5
<rules>
<requireMavenVersion>
<version>[3.5.4,)</version>
</requireMavenVersion>
</rules>

所以会报错

查看源图像

1
2
3
4
5
Detected Maven Version: 3.5.0 is not in the allowed range [3.5.4,).

[INFO] ------------------------------------------------------------------------

[INFO] BUILD FAILURE

去dockerhub上找了个镜像image ‘maven:3.6.1-alpine’

问题解决

3,没有权限权限

然后到了最后一步Deliver

按照官方的写法

1
2
3
4
5
stage('Deliver') { 
steps {
sh './jenkins/scripts/deliver.sh'
}
}

结果报错

1
2
3
4
5
+ ./jenkins/scripts/deliver.sh

/var/jenkins_home/workspace/demo1@tmp/durable-aed01882/script.sh: line 1: ./jenkins/scripts/deliver.sh: Permission denied

script returned exit code 126

主要是这个问题困扰了我好久

在网上看到的解决方案,基本上都是改用户,改文件权限。我试了都不行。

因为我用docker启动的时候就指定了用户是root

并不是jenkins

然后我修改了下stage,加上了sleep(100)

让容器暂停下,不要很快的退出。

1
docker exec -it 9ee087b880b9 /bin/sh

进到容器里,我执行了下

1
sh ./jenkins/scripts/deliver.sh

是成功的,没问题啊。

然后又仔细看了下报错,原来jenkins是直接执行的

1
./jenkins/scripts/deliver.sh

并不是

1
sh ./jenkins/scripts/deliver.sh

原来如此啊。之前deliver.sh它并不是一个可执行文件,直接执行自然是不行的。

那么简单的只要改一下

1
2
3
4
5
stage('Deliver') { 
steps {
sh 'sh ./jenkins/scripts/deliver.sh'
}
}

或者

1
2
3
4
5
6
stage('Deliver') {
steps {
sh 'chmod +x ./jenkins/scripts/deliver.sh'
sh './jenkins/scripts/deliver.sh'
}
}

成功。yes

image-20220706172750671

Jenkins语法

environment

用来定义环境变量。环境变量的作用范围,取决你environment{…}所写的位置,你可以写在顶层环境变量,让所有的stage下的step共享这些变量。如果定义在某个stage下,那么其他stage里的step就不能使用这些变量。

一般而言,我们都是用environment定义全局变量,局部变量用def关键字定义即可。

举例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
environment {
REGISTRY = 'harbor-test.xxx.net
HARBOR_NAMESPACE = 'dddd
APP_NAME = 'notice-tool'
APP_VERSION = '1.0.0'
}

stage('build img') {
steps {
script {
sh 'docker build -t $REGISTRY/$HARBOR_NAMESPACE/$APP_NAME:$APP_VERSION .
}
}
}

env

内置的环境变量,可以直接使用

举例

1
2
3
4
if (env.BRANCH_NAME == 'master') {
// 如果是master分支,xxxxx
println env.WORKSPACE // 打印当前工作目录
}

内置环境变量有很多

WORKSPACE 当前工作目录
BRANCH_NAME 当前分支

内置方法

dir()

改变当前的工作目录

举例

1
2
3
dir("${env.WORKSPACE}/testdata"){   //切换到当前工作目录下的testdata目录
sh "pwd" //sh命令可以 sh "command..." 也可以 sh("command....")
}

deleteDir()

清空当前目录

KubeSphere CI/CD

KubeSphere CI/CD 流水线工作流

KubeSphere CI/CD 流水线基于底层 Kubernetes Jenkins Agent 而运行。这些 Jenkins Agent 可以动态扩缩,即根据任务状态进行动态供应或释放。Jenkins Controller 和 Agent 以 Pod 的形式运行在 KubeSphere 节点上。Controller 运行在其中一个节点上,其配置数据存储在一个持久卷声明中。Agent 运行在各个节点上,但可能不会一直处于运行状态,而是根据需求动态创建并自动删除。

当 Jenkins Controller 收到构建请求,会根据标签动态创建运行在 Pod 中的 Jenkins Agent 并注册到 Controller 上。当 Agent 运行完任务后,将会被释放,相关的 Pod 也会被删除。

动态供应 Jenkins Agent

动态供应 Jenkins Agent 有以下优势:

资源分配合理:KubeSphere 动态分配已创建的 Agent 至空闲节点,避免因单个节点资源利用率高而导致任务排队等待。

高可扩缩性:当 KubeSphere 集群因资源不足而导致任务长时间排队等待时,您可以向集群新增节点。

高可用性:当 Jenkins Controller 故障时,KubeSphere 会自动创建一个新的 Jenkins Controller 容器,并将持久卷挂载至新创建的容器,保证数据不会丢失,从而实现集群高可用。

传统的 Jenkins Controller-Agent 架构(即多个 Agent 为一个 Controller 工作)有以下不足。

  • 如果 Controller 宕机,整个 CI/CD 流水线会崩溃。
  • 资源分配不均衡,一些 Agent 的流水线任务 (Job) 出现排队等待,而其他 Agent 处于空闲状态。
  • 不同的 Agent 可能配置环境不同,并需要使用不同的编码语言。这种差异会给管理和维护带来不便

agent

代理。

agent 部分指定整个流水线或特定阶段 (Stage) 将在 Jenkins 环境中执行的位置,具体取决于该 agent 部分的放置位置。

ks内置 podTemplate

podTemplate 是一种 Pod 模板,该 Pod 用于创建 Agent。用户可以定义在 Kubernetes 插件中使用的 podTemplate。

当流水线运行时,每个 Jenkins Agent Pod 必须具有一个**名为 jnlp 的容器,用于 Jenkins Controller 和 Jenkins Agent 之间进行通信。**另外,用户可以在 podTemplate 中添加容器以满足自己的需求。

在目前版本中,KubeSphere 内置了 4 种类型的 podTemplate:basenodejsmavengo,并且在 Pod 中提供隔离的 Docker 环境。

图生图

图生图的本质其实就是用 prompt 引导原始图像产生新的图像

Denoising strength(重绘强度)

重绘强度仅在图生成图(img2img)或高清修复过程中被应用,这个变量表示图像加噪的程度。它代表了生成的图像相对于原始输入图像内容的变化程度,数值越高,AI 对原图的参考程度就越低,而与prompt关联性却越高,生成的图像和原图的区别就越大。

采样步数为 30,重绘强度取 0.6 便是不错的选择

采样器

我们已经知道 AI 绘画的精髓就是一个一步一步去除噪声的过程。在每一步的去噪过程中,关键的组件就是采样器。

在任意一步x,我们有当前的有噪声的图像,和通过unet输出上一步的噪声。进而求得上一步的噪声图像。

将当前步的有噪声的图像,减去上一步的噪声图像,就可以得到上一步的有噪声的图像。

这个减的过程就需要采样器。

加噪的过程有 1000 步,但是将噪不需要这么多,通常20到30次就可以了。一次可以去除50个噪声。

WebUI 中怎样选择合适的采样器

  • Euler,可以看作是最简单的求解器。

  • Heun,比欧拉法更准确但速度较慢。

  • LMS (Linear multi-step method),与欧拉法速度差不多,但(据说)更准确。

  • DPM(扩散概率模型求解器)和 DPM++ 采样器是 2022 年发布的专为扩散模型设计的新采样器。

DDIM(去噪扩散隐式模型)和 PLMS(伪线性多步方法)这两个采样器目前通常被认为已经过时,并且不再广泛使用

几个选择采样器的建议。

  • 如果你想使用快速、新颖且质量不错的算法,最好的选择是 DPM++ 2M Karras,设置 20~30 步。
  • 如果你想要高质量的图像,那么可以考虑使用 DPM++ SDE Karras,设置 1015 步,但要注意这是一个计算较慢的采样器。或者使用 DDIM 求解器,设置 1015 步。
  • 如果你喜欢稳定、可重现的图像,请避免使用任何原始采样器(SDE 类采样器)。
  • 如果你喜欢简单算法,Euler 和 Heun 是不错的选择。

周末在家里的17年买的小米笔记本上安装了stable-diffusion,实践证明运行sd并不需要配置很高的电脑,如果只是想玩一玩,完全可以在自己的电脑上安装体验一下。

自己部署的模型,要比在mj,或者各种网站上更自由。可以去huggingface或者civitai网站上找自己感兴趣的模型进行部署。

当然如果想要作为生产力工具,还是必须上配置了。

安装python

没有用anacoda,直接装的python3.10.6

官方建议的python版本就是3.10.6。按照官方的来准没错。

安装git

都是开发,略。

安装stable-diffusion-webui

去stable-diffusion-webui的官方github下载

AUTOMATIC1111/stable-diffusion-webui: Stable Diffusion web UI (github.com)

运行webui-user.bat即可

根据stable-diffusion-webui官方的说法,只需要这三步就可以运维sd-webui了。

如果你的运气比较好,到这步可能就直接成功了。那么后面的也就不用看了。

但如果你和我一样,电脑不是很给力,可能也会遇到各种报错。

下面就是我解决各种报错后一个整理。

提示

安装过程中会下载很多依赖包和模型,都很大。所以提前规划去比较大的硬盘空间。至少30G,以后下载的模型都是G起步的。

另外安装过程中可能需要去外面下载一些文件,所以网络上也打通比较好。我安装的时候是开着的。

最开始遇到的报错是cuda disable。所以去安装cuda

安装cuda

cuda是啥?

CUDA通过CPU任务分发和GPU并行处理的方式,把计算任务通过CPU分发给GPU进行并行计算加速。应用程序通过可以CUDA编译器将程序转化为可以在英NVIDIA GPU上执行的机器码快速运行。

win10+英伟达mx150安装cuda,cudnn,GPU版本pytorch-CSDN博客

我这台电脑是双显卡,英伟达的显卡是GeForce MX150

image-20240810233036974

查看NVIDA显卡的驱动版本

桌面右键->NVIDIA控制面板->帮助->系统信息

image-20240811084057836

查看cuda所需要的显卡驱动版本

1. CUDA 12.6 Release Notes — Release Notes 12.6 documentation (nvidia.com)

显卡驱动版本只要大于cuda对应的最低版本就行

image-20240811084259668

找到对应电脑的cuda版本。我这里选择10.1

CUDA Toolkit Archive | NVIDIA Developer

image-20240811084603172

下载完成后安装即可。

image-20240811094926981

安装完成后,使用nvcc看一下

1
nvcc -V

image-20240811100508343

这样就是安装成功了

安装cuDNN

cuDNN 是 NVIDIA 的 CUDA 深度神经网络库,可以显著提高训练速度和推断速度。

cuDNN要匹配CUDA的版本,下载地址:https://developer.nvidia.com/rdp/cudnn-archive

image-20240811121144255

下载解压之后,把里面的全部文件复制到cuda的安装文件夹

之前cuda的默认安装目录是C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.1

最后可以测试一下cudnn是否安装ok

在extras/demo_suite下有个bandwithTest.exe。执行下,result = PASS

image-20240811195913840

安装pytorch

地址 PyTorch

image-20240811200900500

最低的是cuda 11.8。估计不行,姑且试试吧

pip3 install torch torchvision torchaudio –index-url https://download.pytorch.org/whl/cu118

安装完成后,测试一下

1
2
import torch
torch.cuda.is_available()

报错,说有依赖的dll文件没找到。

image-20240810231824923

解决:

下载 dll 文件依赖分析工具 Dependencies

下载地址:https://github.com/lucasg/Dependencies/tree/v1.11.1

使用 Dependencies 分析报错 ddl 文件的依赖

发现是libomp140_x86_64这个依赖没有

去下面这个网站上可以下载到

libomp140.x86_64.dll : Free .DLL download. (dllme.com)

image-20240810231743447

再次尝试,又悲剧了

image-20240811200724002

显卡驱动太低。其实之前装cuda是10.1。pytorch要求的cuda是11.8,所以不行。

从头再来,升级显卡驱动

NVIDIA GeForce 驱动程序 - N 卡驱动 | NVIDIA

image-20240811201114948

下了一个最新的

image-20240811201216185

安装好新驱动,傻瓜式安装即可

image-20240811202703950

更新驱动之后,重新安装cuda,cudnn,pytorch

pytorch我这次可以安装12.4版本了

1
pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu124

image-20240811215328749

ok了

stable-diffusion-webui成功

去stable-diffusion-webui的官方github下载

AUTOMATIC1111/stable-diffusion-webui: Stable Diffusion web UI (github.com)

运行webui-user.bat即可

下载了一堆东西。所以一定要找一个空间大的盘。

image-20240811223435653

可以看到sd-webui又去下载了torch。所以我这里也怀疑其实不需要自己手动安装pytorch。

启动成功之后,服务运行在7860端口

赶紧生成一个试试

1
cat

image-20240812073547811

感觉不是很好啊

00008-3897014488

去网上找了段prompt

1
city future, 8k, exploration, cinematic, realistic, unreal engine, hyper detailed, volumetric light, moody cinematic epic concept art, realistic matte painting, hyper photorealistic

反向提示词

1
lowres, bad anatomy, text, error, extra digit, fewer digits, cropped, worst quality, low quality, normal quality, jpeg artifacts,signature, watermark, username, blurry, artist name

image-20240812071322701

这个生成的还不错

00007-807413399

看我可怜的4G的显存,都是跑满的。

image-20240811234044069

我这台电脑,生产一张512x512,20步的图,大约5分钟。还是相当慢的。

日常技术总结

同时欢迎关注公众号 技术笔记与开源分享

我的二维码

元素法典——Novel AI 元素魔法全收录 (qq.com)

初级

标签

比如 “best quality” 和 “masterpiece”

负向提示词(negative prompt)

不要出现的特征

比如生产的图片某些部分有瑕疵,可以在负向里直接写上这个瑕疵。

提示词权重

()括号括起来的,权重更高

()单括号默认情况下会让对应的单词产生 1.1 倍的强度。双括号 (()) ,则表示 1.1 x 1.1 倍的加强。

我们也可以直接将数字写上去,例如 (dog:1.2) 。

但是要注意,不建议将权重设置超过 1.3,否则对画面的影响很大,甚至不能产生正常的图像。

CFG Scale 提示词相关性

CFG Scale,也就是我们常说的 “提示词相关性”。CFG Scale 在有的教程中也叫 Guidance Scale,二者是一回事

在 WebUI 中,CFG Scale 的范围是 1-30,默认值为 7

中级

引入 LoRA

SD模型是一种大模型,LoRA就是对SD大模型进行快速微调的技术。

LoRA 模型可以看作是原始模型的新特效,你可以这样理解:LoRA 相当于给原有模型穿上了“新服饰”一样,能让图像呈现出不同的风格表现。

LoRA 的本质是冻结住 Stable Diffusion 模型的参数,重新微调很少一部分的模型参数,使用这部分参数对原始的 Stable Diffusion 模型参数进行干预。研究发现,LoRA 的微调质量与全模型微调相当,所以没有 256 块 A100 显卡的我们也能训练自己的 AI 绘画模型。

可以在prompt区域引入LoRA。标准写法是 <lora: 模型文件名: 权重 >

权重的范围是 0 到 1,其中 0 表示 LoRA 模型完全不起作用。

WebUI 会自动加载相应的 LoRA 模型,并根据权重的大小进行应用。

这些 LoRA 文件可以是自己训练的,你也可以从开源社区获取。

比如我们去Civitai 开源社区下载一个loRA模型。

下载后放在stable-diffusion-webui/models/Lora 文件夹

之后就可以在 WebUI 中看到这个模型了

ControlNet

控制sd模型,不要太过自由发挥。

Stable Diffusion,(以后简称SD)。首先理解名字。翻译过来就是稳定扩散。为啥叫这个名字?因为sd是基于扩散(diffusion)模型。

严格说来它是一个由几个组件(模型)构成的系统,而非单独的一个模型。

顺便说一句,Midjourney 也是基于diffusion模型。

sd工作原理

扩散模型画图的原理和雕刻很像。就像米开朗基罗的话:雕塑本来就在这块石头里,我只是把无用的部分去掉。

扩散模型画图就是将无用部分去掉的过程。sd从一个随机噪声图出发,逐步去除噪声,最终生成一张高质量的图片

基于扩散模型实现 AI 绘画的精髓就在于,如何实现这个逐步去除噪声的过程。在每一步的去噪过程中,起作用的是一个需要训练的神经网络,也就是一个 UNet

以文生图为例,

当我们输入一句 prompt 后,比如“Cat, standing on the table”,SD会生成一张猫站在桌子上的图,看似只有一步。

但SD实际上进行了以下三大步骤

  1. 用户输入的 Prompt 会被一个叫 Text Encoder(文本编译器)的东西编译成一个个的词特征向量。此步骤下会输出 77 个等长的向量,每个向量包含 768 个维度。现在可以简单将其理解为「将文本转化为机器能识别的多组数字」。

  2. 这些特征向量会和一张随机图(可以简单理解这是一张布满电子雪花的图,或充满信息噪声的图),一起放到 Image Information Creator 里。在这一步,机器会将这些特征向量和随机图先转化到一个 Latent Space(潜空间)里,然后根据这些特征向量,将随机图「降噪」为一个「中间产物」。你可以简单理解,此时的「中间产物」是人类看不懂的「图」,是一堆数字,但此时这个中间产物所呈现的信息已经是是一只站在桌子上的猫了

  3. 最后,这个中间产物会被 Image Decoder(图片解码器)解码成一张真正的图片

  • Stable Diffusion checkpoint:这里可以选择已经下载的模型。目前许多平台支持开源的 SD 模型下载,例如 Civitai、Hugging Face 等。

  • txt2img:这个选项表示启用文生图(text-to-image)功能。类似地,img2img 等选项则代表其他功能。

  • prompt:用于生成图像的文字输入,需要使用英文输入,但你也可以通过探索 Extensions 来实现中文输入。

  • negative prompt:这是生成图像的反向提示词,用于指定你不希望模型生成的内容。例如,如果你不想图像中出现红色,可以在这里输入“red”。

  • Sampling method:不同的采样算法,这里深入了 Diffusion 算法领域,稍后我们会更详细地讲解。简单来说,通过这些采样算法,噪声图像可以逐渐变得更清晰。

  • Sampling steps:与采样算法配合使用,表示生成图像的步数。步数越大,需要等待的时间越长。通常 20-30 步就足够了。

  • Width & Height:生成图像的宽度和高度。

  • Batch size:每次生成的图像数。如果显存不够大,建议调小这个数值。

  • CFG scale:这里表示 prompt 的影响程度。值越大,prompt 的影响就越大。

  • Seed:生成图像的随机种子,类似于抽奖的幸运种子,会影响生成的图像结果。

模型内包含海量的权重参数,我们下载的动辄几GB的权重,存储的主要就是这些数值。你可以理解为,这些权重参数被用于完成复杂的计算,得到我们预期的AI绘画结果。