【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.txt RUN 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

# 利用緩存安裝依賴,設置requirements
ADD ./requirements.txt /src/requirements.txt
RUN 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/v1
kind: Deployment
metadata:
  namespace: {{NAMESPACE}}
  name:mock
  labels:
    app:mock
spec:
  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: Service
apiVersion: v1
metadata:
  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/v1beta1
kind: Ingress
metadata:
  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環境

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM