一、背景
随着AI大模型的应用越来越广泛,编程语言Python也更显得更加实用。
许多对接AI的库都是先在python中应用,才逐步推广至其他编程语言。
接下来,我们将介绍python编程的CI/CD流程及其实现。
包括以下几个部分:
- jenkins pod template配置
- jenkins jenkinsfile文件
- jenkins job配置
- docker私有仓库
- k8s的deployment和service(略)
限于篇幅,将按CI/CD分为两部分,本文阐述CI部分,有了docker镜像,想要部署到k8s就容易了。(换句话说,k8s部署本身是不区分语言,java还是python,或者go等等)
二、pod template

1、新增pod template


输入Pod模板的名称和命名空间。
2、新增容器jnlp
jenkins集群是采用k8s动态扩展,每运行一个job,就是创建一个k8s pod节点,所以job之间互不干扰。

jnlp镜像是我自己私库的地址,你可以使用外网的,更倾向于使用私库的。
3、新增容器docker
制作docker镜像,推送至仓库

4、配置pod环境变量

5、添加卷

docker镜像必须要添加Host Path Volume,主机路径和挂载路径均为/var/run/docker.sock

6、拉取镜像的Secret

7、节点选择器
保证pod是在worker角色的节点上创建。node-role.kubernetes.io/worker=worker

三、jenkinsfile
docker构建并推送至私库,封装在类docker.groovy里
- 版本号默认写在项目的根目录的.version文件里
- 项目的根目录还需要编写自己的Dockerfile文件,用于构建docker镜像
因为编译打包的过程都在Dockerfile中,所以整个jenkinsfile的流程就三步:
- 第一步,拉取git代码
- 第二步,读取程序的版本号
- 第三步,构建docker镜像,并推送
对项目的要求,见下图:

bash
#!groovy
@Library('jenkinslib') _
// gitlab的ssh密钥,修改为你自己的
String gitlabCredentialsId = "xxx"
def tools = new com.xxx.devops.tools()
def docker = new com.xxx.devops.docker()
// 服务名称
String serviceName = "${env.serviceName}".trim()
//git代码地址
String codeUrl = "${env.codeUrl}".trim()
//git代码分支
String branch = "${env.branch}".trim()
// 版本号
String appVersion = ""
// 版本号文件
String versionFileName = "${env.versionFile}".trim()
if (versionFileName == "" || versionFileName == "null") {
versionFileName = ".version"
}
// 默认读取项目工作空间中的Dockerfile
String dockerfileName = "Dockerfile"
pipeline {
agent {
kubernetes {
inheritFrom 'jnlp-python'
}
}
options {
timestamps() //日志会有时间
skipDefaultCheckout() //删除隐式checkout scm语句
disableConcurrentBuilds() //禁止并行
timeout(time: 1, unit: 'HOURS') //流水线超时设置1h
}
stages {
stage('Pull Code') {
steps {
script {
tools.PrintMes("pull code!!!", "green")
git branch: "$branch", credentialsId: "$gitlabCredentialsId", url: "$codeUrl"
}
}
post {
failure {
//当此Pipeline失败时打印消息
script {
tools.PrintMes("pull code failure!!!", "red")
}
}
}
}
stage('Get Version') {
steps {
script {
tools.PrintMes("Get Version!!!", "green")
dir("${env.WORKSPACE}") {
sh "cat ${versionFileName}"
String version = sh returnStdout: true,
script: """
cat ${versionFileName}
"""
// trim()
appVersion = version.trim()
}
// 输出程序的版本号
tools.PrintMes("get version: ${appVersion}", "green")
}
}
post {
failure {
//当此Pipeline失败时打印消息
script {
tools.PrintMes("Get Version failure!!!", "red")
}
}
}
}
stage('Push Docker Image') {
steps {
script {
tools.PrintMes("Push Docker Image!!!", "green")
container('docker') {
dir("${env.WORKSPACE}") {
if ("PROD" == buildEnv) {
docker.pushToAly(serviceName, appVersion, dockerfileName)
} else {
docker.pushToNexus(serviceName, null, appVersion, null, dockerfileName, "python")
}
}
}
}
}
post {
failure {
//当此Pipeline失败时打印消息
script {
tools.PrintMes("Push Docker Image failure!!!", "red")
}
}
}
}
}
post {
success {
//当此Pipeline成功时打印消息
script {
tools.PrintMes("archive zip, send the message of build successfully to user", "green")
dir("${env.WORKSPACE}") {
sh "echo ${appVersion} > .version"
archiveArtifacts artifacts: '.version', followSymlinks: false
}
}
}
failure {
//当此Pipeline失败时打印消息
echo 'failure'
}
unstable {
//当此Pipeline 为不稳定时打印消息
echo 'unstable'
}
aborted {
//当此Pipeline 终止时打印消息
echo 'aborted'
}
changed {
//当pipeline的状态与上一次build状态不同时打印消息
echo 'changed'
}
}
}
三、jenkins job配置

围绕上文的jenkinfile,输入变量主要是三个:
- serviceName: 服务名,docker镜像名
- codeUrl: git项目地址
- branch:代码分支
这里还支持版本号写在别的文件里。
- versionFile 版本文件名,默认是.version,如果是其他,则需要输入
jenkins job 除了配置变量外,关键是配置jenkinsfile所在的git地址、分支以及相对路径。

四、docker私有仓库
- 1、构建docker镜像
- 2、登录docker私服
- 3、给本地docker镜像打标签
- 4、把本地docker镜像推送到私库
- 5、删除本地docker镜像
下面截图,省略docker build过程,因为它比较耗时,也是Jenkins CI的核心过程。

1、研发环境


2、生产环境
阿里云容器镜像服务,先创建镜像仓库。

jenkins推送docker镜像到阿里云镜像仓库
