「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环境

发表评论
留言与评论(共有 0 条评论) “”
   
验证码:

相关文章

推荐文章