CI/CD:使用 Jenkins 的 Pipeline 测试 python 程序并制作 docker 镜像

上文书实践了 Jendkins 的 freestyle 项目,这次使用 pipeline 进行测试和构建打包

加入自动单元测试

启动 Jenkins 的 docker 以后,freestyle 是通过执行 shell 命令来逐步实现测试、构建和打包的,shell 命令是在 Jenkins 的 docker 容器内执行的,如果要将应用打成 docker 镜像,需要将宿主机的 docker 命令和 socket 文件映射进 Jenkins 的容器里。如果要测试 python 程序的话,直接执行 shell 命令会是在 Jenkins 的容器里面,依赖的 python 版本和库都不具备,所以更好的方式是构建一个测试用的 docker 镜像,运行起来进行测试,测试完后销毁。这个镜像和 python 程序最终要打包成的 docker 镜像的依赖完全一致。

使用 Jenkinsfile 定义 pipeline

Jenkins 的流水线(pipeline)构建方式可以根据一个 Jenkinsfile 文件中声明的步骤来逐步执行 CI/CD 的流程,这个 Jenkinsfile 文件可以放在源码包里由 SCM 进行版本控制。

Jenkins 流程

我这次添加了一个单元测试文件,Jenkinsfile 中增加了自动执行单元测试的步骤,整体流程是

构建测试镜像
执行单元测试
将应用打成 docker 镜像

项目文件

目录结构

flask_docker_jenkins_demo/
├── Dockerfile
├── Jenkinsfile
├── README.md
├── app.py
├── requirements.txt
└── test.py

app.py

from flask import Flask, jsonify

app = Flask(__name__)


@app.route('/')
def hello_world():
    return 'Hello, World!'


@app.route('/hello/<username>')
def hello_user(username):
    return f'Hello {username}'


@app.route('/health')
def health_checking():
    ret = {'status': 'UP'}
    return jsonify(ret)


if __name__ == '__main__':
    app.run(port=5000, debug=False)

test.py

import unittest
import app


class TestHome(unittest.TestCase):
    def setUp(self):
        app.app.testing = True
        self.app = app.app.test_client()

    def test_home(self):
        res = self.app.get('/')
        self.assertEqual(res.status, '200 OK')
        self.assertEqual(res.data, b'Hello, World!')

    def test_hello_user(self):
        name = 'Yngwie'
        res = self.app.get(f'/hello/{name}')
        self.assertEqual(res.status, '200 OK')
        self.assertIn(bytearray(f'{name}', 'utf-8'), res.data)


if __name__ == '__main__':
    import xmlrunner
    runner = xmlrunner.XMLTestRunner(output='test-reports')
    unittest.main(testRunner=runner)
    unittest.main()

requirements.txt

Flask
gunicorn
xmlrunner

Dockerfile

FROM python:3.6.9-alpine

ADD . /app

RUN pip install --no-cache-dir -i http://mirrors.aliyun.com/pypi/simple/ \
--trusted-host mirrors.aliyun.com -r /app/requirements.txt

ENV GUNICORN_CMD_ARGS="--bind=0.0.0.0:5001 --chdir=./app/ --workers=2"

CMD ["gunicorn", "app:app"]

Jenkinsfile

pipeline {
  agent none
  stages {
    stage('build and test') {
      agent { docker { image 'python:3.6.9-alpine' } }
      stages {
        stage('build'){
          steps {
            sh 'pip install --no-cache-dir -r requirements.txt'
          }
        }
        stage('test') {
          steps {
            sh 'python test.py'
          }
          post {
            always {
              junit 'test-reports/*.xml'
            }
          }
        }
      }
    }
    stage('build docker image'){
      agent any
      steps{
        sh 'docker build -t my-flask-image:latest .'
        sh 'a=`docker images -f "dangling=true" -q | wc -l`'
        sh 'if [ $a -ge 0 ];then docker rmi $(docker images -f "dangling=true" -q);fi'
      }
    }
  }
}

Jenkins 配置

Jenkins 任务

扫描二维码关注公众号,回复: 9412611 查看本文章
  1. 【新建任务】 - 起名,选择流水线类型 - 确定
  2. 【构建触发器】 - 【轮询 SCM】 - 【日程表】填* * * * *
  3. 【流水线】 - 【定义】 - 选【Pipeline script from SCM】 - 【SCM】- 选【Git】,填写仓库地址 - 【脚本路径】 - 填Jenkinsfile - 保存

注意

Jenkinsfile 中根 agent 设置为 none,这样可以在后续的 stages 和 stage 中跟别定义不同的 agent,测试使用临时构建的 docker 镜像,而打包要使用Jenkins 的 docker 容器执行,容器执行宿主机映射进来的 docker 命令。

完成

这样,在每次向代码库 push 新的代码以后,Jenkins 会自动拉取代码,构建测试镜像测试,然后打包成 docker 镜像。

发布了66 篇原创文章 · 获赞 21 · 访问量 8万+

猜你喜欢

转载自blog.csdn.net/qq_35753140/article/details/104082790