使用Kubernetes集群作为工作节点 在前面那个简单的pipeline中实际并没有做什么东西,同时它的工作任务也是运行在Jenkins主节点的,现在,给Jenkins添加一个Kubernetes集群作为worker节点,当有任务开始执行的时候,让他在集群中自动创建一个pod,然后再这个pod内完成所有工作,最后任务执行结束,销毁这个pod.
添加Kubernetes作为工作节点 首先安装Kubernetes
插件.
系统管理 -> 节点管理
文章图片
然后配置集群apiserver等地址
文章图片
文章图片
文章图片
文章图片
开始使用 首先先来一个比较简单的操作,比如拉取代码.
首先,Git新建项目,然后上传一个名为cpu.py
的文件,内容:
from flask import Flask
app = Flask(__name__)@app.route("/")
def main():
number = 0
for i in range(0,100000000):
number+=i
return {"key":number}if __name__ == '__main__':
app.run(host='0.0.0.0',port="8000")
然后Jenkins添加对应的密钥,在01文章中给gitlab添加了一个拉取代码的密钥,现在Jenkins也需要添加一下.
查看密钥
cat ~/.ssh/id_rsa
文章图片
文章图片
文章图片
文章图片
保存后自动返回,填写git地址等.
文章图片
然后点击"生成流水线脚本",替换下面代码中的
git branch ....
等内容.实际直接复制新建凭据的ID替换掉,然后修改对应拉取代码的地址即可
podTemplate(
cloud: 'kubernetes'
) {
node(POD_LABEL) {
stage('pull code') {
// 克隆代码
git branch: 'main', credentialsId: 'd17b1091-fa2d-4310-8a4d-0b1d7f823ea9', url: 'ssh://git@20.88.9.34:222/my_group/one_project.git'
// 打印信息
echo "The first stage end"
}
}
}
手动执行:
文章图片
第一步成功.
模拟编译和构建镜像 获取到了代码,接下来就是如何对代码进行编译,然后打包推送仓库的问题了.
Python代码可以用pyinstaller命令将其编译为一个二进制文件,通过二进制文件可以再不同的主机运行并且不需要Python环境没有找到Jenkins有对应支持pipeline的插件,自己制作一个镜像,里面包含这个命令即可.
FROM python:3.6.15-slim
RUN apt-get update -y
RUN apt-get install binutils -y
RUN /usr/local/bin/python -m pip install --upgrade pip -i https://pypi.tuna.tsinghua.edu.cn/simple
RUN pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pyinstaller
ADD start.sh start.sh
CMD ["sleep","99d"]
docker build -t 528909316/jenkins:pyinstaller_v1 .
# 推送到远程仓库
docker push 528909316/jenkins:pyinstaller_v1
接下来,就是如何让Jenkins的slave节点在这个容器中运行了.
podTemplate(
cloud: 'kubernetes',
containers: [
// 定义一个pod模板
containerTemplate(name: 'build', image: '528909316/jenkins:pyinstaller_v1', command: "sleep 99d", ttyEnabled: true)]
) {
node(POD_LABEL) {
// 步骤1: 拉取代码
stage('pull code') {
// 克隆代码
git branch: 'main', credentialsId: 'd17b1091-fa2d-4310-8a4d-0b1d7f823ea9', url: 'ssh://git@20.88.9.34:222/my_group/one_project.git'
echo "The first stage end"
}
// 步骤2: 编译代码
stage('build code') {
container('build') {
stage('Build a python project') {
// 编译为文件
sh '''
pyinstaller -F cpu.py
'''
}
}
echo "The second stage end."
}
}
}
如上的代码中定义了一个pod模板.继续开始添加下一个过程: 制作镜像推送到远程仓库
默认Jenkins会为slave创建一个pod,然后在里面启动一个容器来运行所有的工作任务.pod中多个容器的存储是共享的,所以这里的容器模板实际上是在这个pod中新增了一个容器,这个容器具有pyinstaller
命令.当主容器拉取到代码后,会执行步骤2的编译过程.
同样新增一个具有docker命令的容器,不同的是这个容器如果想使用docker命令需要先启动服务,通过/var/run/docker.sock文件和服务通信完成.容器中没有办法再启动一个docker,但是主机上(Kubernetes容器运行时使用的docker)是有这个文件的,所以将主机文件挂载到pod中,让容器中的程序直接和主机docker进程通信.
涉及知识点: 一切皆文件制作一个包含docker命令的镜像
FROM alpine:3.14
RUN echo 'http://mirrors.aliyun.com/alpine/v3.8/main/' >/etc/apk/repositories;
echo 'http://mirrors.aliyun.com/alpine/v3.8/community/'>>/etc/apk/repositories
RUN apk add docker
CMD ["sleep","99d"]
执行命令
docker build -t 528909316/jenkins:rundocker_v1 .
推送到仓库,接下来还要再gitlab中也添加一个Dockerfile,来定义制作这个镜像的过程.
名称自然是Dockerfile,内容:
FROM python:3.6.15-slim
RUN /usr/local/bin/python -m pip install --upgrade pip -i https://pypi.tuna.tsinghua.edu.cn/simple
RUN pip install -i https://pypi.tuna.tsinghua.edu.cn/simple flask
ADD cpu.py cpu.py
CMD ["python","cpu.py"]
继续修改pipeline文件
podTemplate(
cloud: 'kubernetes',
containers: [
// 容器模板1 : 编译镜像
containerTemplate(name: 'build', image: '528909316/jenkins:pyinstaller_v1', command: "sleep 99d", ttyEnabled: true),
// 容器模板2: 制作docker镜像
containerTemplate(name: 'docker', image: '528909316/jenkins:rundocker_v1', command: "sleep 99d", ttyEnabled: true)],
// 挂载卷: hostPathVolume为主机目录或文件,将主机的/var/run/docker.sock文件挂载到pod的/var/run/docker.sock
volumes: [hostPathVolume(hostPath: '/var/run/docker.sock', mountPath: '/var/run/docker.sock')]
) {
node(POD_LABEL) {
stage('pull code') {
// 克隆代码
git branch: 'main', credentialsId: 'd17b1091-fa2d-4310-8a4d-0b1d7f823ea9', url: 'ssh://git@20.88.9.34:222/my_group/one_project.git'
echo "The first stage end"
}
stage('build code') {
container('build') {
stage('Build a python project') {
// 编译为文件
sh '''
pyinstaller -F cpu.py
'''
}
}
echo "The second stage end."
}
// 步骤3 :构建docker镜像
stage("build image") {
container("docker") {
stage("build image") {
// build 镜像
sh "docker build -t 528909316/jenkins:taskcpu_v1 ."
// 登陆docker仓库
sh "docker login -u 528909 -p '**********'"
// 推送镜像
sh "docker push 528909316/jenkins:taskcpu_v1"
}
}
echo "push end."
}
}
}
部署到k8s 拉取代码,编译,制作镜像都完成了,接下来只剩下一件事情: 部署应用到k8s
在此选择了使用
Kubernetes Continuous Deploy
组件.官方地址既然是插件自然使用"流水线语法"了,选择组件填写内容,添加一个kubeconfig类型的文件(内容就是Kubernetes主节点的/etc/kubernetes/admin.conf文件内容),然后重新修改pipeline增加一个流水线步骤:
注: 不知为何我安装了最新的2.1.2版本发布一直失败.直到我将版本换为了1.0.0才成功,参考文档:Kubernetes Continuous Deploy插件的使用,文章发布于2019-9,里面提到该插件1.0.0版本比较稳定,所以我也就降低了版本.
发布过程中还要用到一个Kubernetes的编排文件,继续在仓库添加一个名为
deploy.yaml
的文件,内容:apiVersion: apps/v1
kind: Deployment
metadata:
name: python-cpu
spec:
selector:
matchLabels:
run: python-cpu
replicas: 1
template:
metadata:
labels:
run: python-cpu
spec:
containers:
- name: python-cpu
image: 528909316/version:run_cpu1
ports:
- containerPort: 8000
resources:
limits:
cpu: 500m
requests:
cpu: 200m
---
apiVersion: v1
kind: Service
metadata:
name: python-cpu
labels:
run: python-cpu
spec:
ports:
- port: 8000
selector:
run: python-cpu
podTemplate(
cloud: 'kubernetes',
containers: [
containerTemplate(name: 'jenkins', image: 'jenkins/jnlp-slave:4.9-1-alpine', command: "sleep 99d", ttyEnabled: true),
containerTemplate(name: 'build', image: '528909316/jenkins:pyinstaller_v1', command: "sleep 99d", ttyEnabled: true),
containerTemplate(name: 'docker', image: '528909316/jenkins:rundocker_v1', command: "sleep 99d", ttyEnabled: true)],
volumes: [hostPathVolume(hostPath: '/var/run/docker.sock', mountPath: '/var/run/docker.sock')]
) {
node(POD_LABEL) {
stage('pull code') {
// 克隆代码
git branch: 'main', credentialsId: 'd17b1091-fa2d-4310-8a4d-0b1d7f823ea9', url: 'ssh://git@20.88.9.34:222/my_group/one_project.git'
echo "The first stage end"
}
stage('build code') {
container('build') {
stage('Build a python project') {
// 编译为文件
sh '''
pyinstaller -F cpu.py
'''
}
}
echo "The second stage end."
}
stage("build image") {
container("docker") {
stage("build image") {
sh "docker build -t 528909316/jenkins:taskcpu_v1 ."
sh "docker login -u 528909 -p '**********'"
sh "docker push 528909316/jenkins:taskcpu_v1"
}
}
echo "push end."
}
stage("deploy image") {
kubernetesDeploy configs: 'deploy.yml', kubeConfig: [path: ''], kubeconfigId: 'ae92d8dc-053e-409e-ae1b-f6e3f3bbb9f4', secretName: '', ssh: [sshCredentialsId: '*', sshServer: ''], textCredentials: [certificateAuthorityData: '', clientCertificateData: '', clientKeyData: '', serverUrl: 'https://']
}
}
}
手动执行,到Kubernetes集群中查看默认名称空间下查看,pod被创建了!
[root@master ~]# kubectl get pod
NAMEREADYSTATUSRESTARTSAGE
centos-deployment-76dc4d95c9-s2gvf1/1Running010h
python-cpu-cc4cfb466-dkrpd1/1Running060s
到了这一步可以确定,流程已经没有问题了,接下来就是继续完善流水线文件了,首先先把发布的deploy.yml文件中的镜像版本改对,然后继续修改对应的dockerfile将打包好的文件加入到容器中,最后运行这个新制作的镜像!最终的Dockerfile
FROM python:3.6.15-slim
ADD dist/cpu cpu
CMD ["./cpu"]
最终的Jenkins.groovy(pipeline)
podTemplate(
cloud: 'kubernetes',
containers: [
//流水线执行过程中的环境 默认会创建一个jenkins-slave容器作为pod的主容器
// 新增一个叫做 build的容器,使用528909316/jenkins:pyinstaller_v1这个镜像,具有命令pyinstaller
containerTemplate(name: 'build', image: '528909316/jenkins:pyinstaller_v1', command: "sleep 99d", ttyEnabled: true),
// 新增一个叫做 docker 的容器,具有命令 docker
containerTemplate(name: 'docker', image: '528909316/jenkins:rundocker_v1', command: "sleep 99d", ttyEnabled: true)],
volumes: [hostPathVolume(hostPath: '/var/run/docker.sock', mountPath: '/var/run/docker.sock')]
) {
node(POD_LABEL) {
stage('pull code') {
// 克隆代码
git branch: 'main', credentialsId: 'd17b1091-fa2d-4310-8a4d-0b1d7f823ea9', url: 'ssh://git@20.88.9.34:222/my_group/one_project.git'
echo "The first stage end"
}
stage('build code') {
container('build') {
stage('Build a python project') {
// 编译为文件 首先更新当前编译环境的pip 然后使用清华源安装flask组件(pyinstaller时当前主机中必须有文件中import的所有包,否则会报错)
// 最后pyinstaller 制作一个叫做cpu的二进制文件,放在 ./dist/目录下
sh '''
python -m pip install --upgrade pip -i https://pypi.tuna.tsinghua.edu.cn/simple
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple flask
pyinstaller -F cpu.py
'''
}
}
echo "The second stage end."
}
stage("build image") {
container("docker") {
stage("build image") {
// 首先docker build 制作一个镜像 然后login登陆一下
sh "docker build -t 528909316/jenkins:taskcpu_v1 ."
sh "docker login -u 528909316 -p 'MyNewPass4!'"
// 最后推送镜像
sh "docker push 528909316/jenkins:taskcpu_v1"
}
}
echo "push end."
}
stage("deploy image") {
// 部署的k8s集群 kubeconfigId为添加的配置在Jenkins的id的名字 创建时没有填写ID的话 Jenkins为为其生成一串随机字符
kubernetesDeploy configs: 'deploy.yml', kubeConfig: [path: ''], kubeconfigId: 'ae92d8dc-053e-409e-ae1b-f6e3f3bbb9f4', secretName: '', ssh: [sshCredentialsId: '*', sshServer: ''], textCredentials: [certificateAuthorityData: '', clientCertificateData: '', clientKeyData: '', serverUrl: 'https://']
}
}
}
最终的deploy.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: python-cpu
spec:
selector:
matchLabels:
run: python-cpu
replicas: 3
template:
metadata:
labels:
run: python-cpu
spec:
containers:
- name: python-cpu
imagePullPolicy: Always
image: 528909316/jenkins:taskcpu_v1
ports:
- containerPort: 8000
resources:
limits:
cpu: 500m
requests:
cpu: 200m
---
apiVersion: v1
kind: Service
metadata:
name: python-cpu
labels:
run: python-cpu
spec:
ports:
- port: 8000
selector:
run: python-cpu
type: LoadBalancer
参考文献
Pipeline Syntax
问题 提示:
Started by user user参考
[Pipeline] Start of Pipeline
[Pipeline] podTemplate
[Pipeline] {
[Pipeline] node
ERROR: Unable to create pod kubernetes jenkins/cluster-one-project-10-stvzm-fl2nv-r8s82.
Failure executing: POST at: https://kubernetes.default.svc.cluster.local/api/v1/namespaces/jenkins/pods. Message: Forbidden!Configured service account doesn’t have access. Service account may have been revoked. pods is forbidden: User “system:serviceaccount:jenkins:default” cannot create resource “pods” in API group “” in the namespace “jenkins”.
[Pipeline] // node
[Pipeline] }
[Pipeline] // podTemplate
[Pipeline] End of Pipeline
Queue task was cancelled
Finished: ABORTED
【devops|03 使用Kubernetes作为工作节点】https://blog.csdn.net/zzb7728317/article/details/106282557/
推荐阅读
- DevOps笔记(脑裂对系统可用性的影响)
- 物联网时代,如何保障嵌入式系统安全()
- Jira工时管理插件(TimeWise for Jira)线上安装量过百,龙智自研产品赢得全球20个国家和地区的企业信赖
- 一文了解游戏美术开发流程,以及可能遇到的问题
- Docker入门(简化DevOps)
- DevOps初学者简介
- DevOps工具的终极清单
- 缩小差距(DevOps通信的重要性)
- "On DevOps: 1. What It Is"