网络知识 娱乐 「Devops」 发布一个Python项目(Flask服务后端)到K8S环境

「Devops」 发布一个Python项目(Flask服务后端)到K8S环境

前言:

有一段时间没有更新博客了,今天给大家分享一下如何将一个python项目成功部署并运行到K8S环境,特做一个记录

准备工作

1. 编写一个python项目,我这边提供的一个Flask服务,提供接口的mock能力。(项目里面编写如下文件)

  1. dockerfile
  2. jenkinsfile
  3. deploy文件夹(内含: deploy.yaml service.yaml ingress.yaml)

流程简释:

jenkinsFile 执行流水线语法---打包docker镜像---把镜像发布到K8s环境(这里用到了deploy的三个文件: deploy,servic,ingress)

必备文件介绍

1. jenkinsFile 【我这里给出的是一个示例,实际要按自己公司的需求和情况来进行部署】

@Library('devops') 指代的是调用的K8S 第三方库(这个用流水线的公司都会提供,发布是基于这个库进行)agent 指代发布的机器使用的是集群里面的slave 标签的机器options 指代jenkins 的一些配置,例如30分钟超时,连接的代码库是(SVN、git、gitlab等等)env 指代发布的时候使用到的一些环境变量,包括发布分支,镜像路径等信息stage 指代jenkins发布的各个阶段

@Library('devops') _String BUILD_RESULT = ""String RELEASE_BUILD=""pipeline { agent { label 'slave' } options { buildDiscarder(logRotator(numToKeepStr: '10')) disableConcurrentBuilds() skipDefaultCheckout() timeout(time: 30, unit: 'MINUTES') gitLabConnection('gitlab') } environment { IMAGE_CREDENTIALS = "credential-harbor" NOTIFY_ACCOUNT= "123456" DEV_BRANCH="dev" QA_BRANCH="v.*" IMAGE_REPOSITORY = "harbor.123.cn/test/mock" BUILD_CONTEXT="build" } stages { stage('Checkout') { steps { script { container('tools') { // checkout code retry(2) { scmVars = checkout scm } env.RELEASE_BUILD = scmVars.GIT_COMMIT BUILD_RESULT = devops.updateBuildTasks(BUILD_RESULT,"Checkout OK...√") echo 'begin checkout...' echo sh(returnStdout: true, script: "env") } } } } stage('build-mock-image') { steps { script { container('tools') { retry(2) { sh """ mkdir -p ${BUILD_CONTEXT}; """ } devops.dockerBuild( "Dockfile", //Dockerfile ".", // build context "${IMAGE_REPOSITORY}", // repo address env.RELEASE_BUILD, // tag IMAGE_CREDENTIALS, // credentials for pushing ).start().push() } } } } stage('deploy-mock') { when { expression { BRANCH_NAME ==~ env.DEV_BRANCH || BRANCH_NAME ==~ env.QA_BRANCH } } steps { script { container('tools') { //create configmap and ingress devops.deploy("", "deploy/ingress.yaml","",false).start() devops.deploy( "deploy", //k8s files dir "deploy/deploy.yaml", RELEASE_BUILD, true ).start() } } } } } post { success { script { container('tools') { devops.notificationSuccess("mock", "流水线完成了", RELEASE_BUILD, "dingTalk") } } } failure { script { container('tools') { devops.notificationFailed("mock", "流水线失败了", RELEASE_BUILD, "dingTalk") } } } }}

2. dockerFile 【制作docker镜像文件,也是一个示范,实际情况实际分析】

 基础镜像使用 -silim 能有效缩减镜像大小 (700-900Mb 缩小到200多Mb 的区别)

ADD ./requirements.txt /src/requirements.txtRUN pip --default-timeout=30 install -i https://mirrors.aliyun.com/pypi/simple/ -r requirements.txt这里先把依赖文件复制过去,后续会读取这个缓存文件进行依赖安装,如果你的requirements 没有改动,则不会触发下载安装,能有效减少发布时间(很多公司的linux机器网络速度很慢)后面指定了国内镜像,也是为了加快依赖的下载速度运行项目可以不执行,因为你发布到K8S, 在deploy.yaml里面一定要执行镜像运行方式注意: 获取requirements文件的方法: pipreqs . (pip install pipreqs)

# 基于的基础镜像FROM python:3.7.5-slim #制作者信息MAINTAINER XXXX #设置工作目录WORKDIR /src# 利用缓存安装依赖,设置requirementsADD ./requirements.txt /src/requirements.txtRUN pip --default-timeout=30 install -i https://mirrors.aliyun.com/pypi/simple/ -r requirements.txt# 复制项目到镜像工作目录ADD . /src # 给镜像下的项目文件赋权RUN chmod a+x /src/*# 运行项目CMD python /src/run.py

3. deploy.yaml 【K8S的入口文件,也是核心发布文件,必需】

namespace 你想发布到K8S的 命名空间app:mock 你发布的项目名称(在k8s里面显示的deploy名称)command: ["/bin/sh"]args: ["-c","python /src/run.py"]----------程序运行命令, 指的是在镜像里面执行的操作,注意python和java的区别即可。containerPort 容器暴露的访问端口,注意这是容器内的,随便定义,但是要保证service、ingress 里面保持一致性,程序启动端口也要用这个。否则无法访问resources 设置了内存和CPU的限制, 这里按机器的实际情况进行设置image 镜像名称

apiVersion: apps/v1kind: Deploymentmetadata: namespace: {{NAMESPACE}} name:mock labels: app:mockspec: minReadySeconds: 10 progressDeadlineSeconds: 20 strategy: rollingUpdate: maxSurge: 1 replicas: 1 revisionHistoryLimit: 1 selector: matchLabels: app:mock template: metadata: labels: app:mock spec: dnsConfig: options: - name: single-request-reopen affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: {{NODE_LABEL_KEY}} operator: In values: - "{{NODE_LABEL_VAL}}" restartPolicy: Always volumes: containers: - name: mock image: {{imageUrl}} imagePullPolicy: IfNotPresent command: ["/bin/sh"] args: ["-c","python /src/run.py"] ports: - containerPort: 9900 resources: requests: memory: "1024Mi" cpu: "500m" limits: memory: "8192Mi" cpu: "4000m"

4. service.yaml 【K8S提供集群内服务访问的文件,开放服务给其他项目调用,必需】

K8S集群调用方式: mock:9900 即---- serviceName:port

kind: ServiceapiVersion: v1metadata: name: mock namespace: {{NAMESPACE}}spec: selector: app: mock ports: - protocol: TCP port: 9900 targetPort: 9900

5. ingress.yaml 【K8S集群提供的外部访问域名文件,用于外部用户通过域名访问服务,非必需】

这里我加入了tls 配置(HTTPS证书访问),secretName为K8S集群里面已存在的证书名称,域名保持一致即可

注意服务名和端口需要和service.yaml对应,即可通过域名访问到服务,如下,通过 mock.test.cn 即可访问mock服务了。

apiVersion: extensions/v1beta1kind: Ingressmetadata: name: mock namespace: {{NAMESPACE}}spec: tls: - hosts: - mock.test.cn secretName: test-cn rules: - host: mock.test.cn http: paths: - backend: serviceName: mock servicePort: 9900 path: /

三、可能遇到的问题

1. Nginx 报错 :

解决: python程序、deploy、service、ingress的端口保持一致性

另外: Flask 暴露的HOST=“0.0.0.0”

[error] *97421558 connect() failed (111: Connection refused) while connecting to upstream, client: 1.1.1.1, server:mock.test.cn, request: "GET /api?taskId=1234 HTTP/1.1", upstream: "http://127.0.0.0:9900/api-waf?taskId=1234", host: "mock.test.cn"

2. 发布到不同分支:

确保你在jenkinsFile 设置了不同分支的名称, 例如你从 dev分支打包, tag是v1.0.0 那么用正则表达式: dev|v.* 可同步发布到test和dev环境