如何使用Flask、Docker和Github行动的持续集成和部署管道

492 阅读6分钟

使用Flask、Docker和Github行动的持续集成和部署管道

DevOps是每个应用程序在行业内部署前后都会经历的实践或阶段。它通过允许对代码库的一系列更新来确保应用程序的持续集成和部署。

CI和CD管道是行业中用于开发和维护每个部署的应用程序的一套做法。从头开始开发应用程序需要这么多的实践,并跟踪每一个变化,以免破坏已经部署在生产中的应用程序。

GitHub Actions是一个由Github提供的自动化工具,它使持续集成变得非常顺利和毫不费力。

在这篇文章中,我们将体验构建一个交互式应用程序。

Docker将应用程序打包成镜像,并将其存储为容器,其配置定义在DockerFile

先决条件

要继续学习本教程,你应该满足以下要求。

  • 对GitHub仓库和Python编程语言的理解。
  • 安装了[Python]。
  • 一个预装的IDE,最好是[Visual Studio Code]。
  • 对[Docker]的理解。
  • 一个Docker Hub账户[Docker Hub]。
  • 对[Flask]的理解。

教学目的

在本教程中,我们将学习使用Docker、Selenium和GitHub行动的持续集成和部署。此外,你还将学习以下内容并将其应用到项目中。

  • 开发和运营概述。
  • 创建一个简单的Flask应用程序。
  • CI和CD管道架构。
  • 使用Github Actions进行持续集成和部署。
  • Docker镜像和容器基础知识。

开发和运营概述

构建管道时涉及不同的阶段,从开发到生产。这些是业内定义的开发和运营管道。

下面的图片描述了所有预先定义的阶段。

DevOps Stages

每个行业在开发应用程序时,都会有以下一系列的做法。

计划

没有一个适当的计划,没有人能够成功地开发一个应用程序。因此,我们必须在踏上开发之旅之前制定一个充分的计划。这时我们要证明技术栈和其他所需的东西。

编码

开发人员在规划阶段确定了需求后,开始了编码部分。然后,他们将通过一个单一的资源库协作来开发应用程序。

构建

在这个阶段,开发的应用程序将被打包,并使用像Docker这样的软件包管理器构建成图像。我们也会将应用程序与启动所需的配置文件一起运送到容器中。

测试

一系列的测试将通过应用程序运行以获得更好的性能。像unit,integrating 等测试,将在开发过程中进行。

测试人员和质量保证工程师可以完成其他测试。有几个工具可以做到这一点,但最受欢迎的是Selenium。运营团队会做其他阶段的工作,它们如下。

发布

这是持续集成阶段开始的地方。只要应用程序有任何更新,这个阶段就会重复无数次。这个行业常用的工具是Jenkins、GitHub Actions、Team City等。

部署

一个通过持续集成阶段的应用程序将进入部署阶段。在使用Ansible、Puppet或Chef进行部署之前,暂存将是这里的第一件事。

操作

部署将完全使用Terraform 等工具开始。然后,完善的应用程序将被部署,并对其操作进行监控。

监控

已部署的应用程序将在性能方面被监控。在监测的同时,将生成日志。在这方面,最流行的工具是SeleniumNagiosELK 等。

一个应用程序在行业中经历了上述所有的实践。熟练掌握所有这些的人就是DevOps Engineer

创建简单的Flask应用程序

打开你喜欢的代码编辑器并导航到终端。运行以下命令来设置你的项目工作流程。

cd ~/Desktop
mkdir flaskdrinks
cd flaskdrinks
python3 -m venv env
source env/Scripts/activate
pip install flask
pip freeze > requirements.txt

你把目录改成了Desktop ,然后做了一个新的目录叫flaskdrinks 。每个Python应用程序都需要一个虚拟环境,env 是这个项目的文件。

此外,你用python包管理器安装了flask的依赖关系,名为pip 。你还用一个名为requirements.txt 的文件跟踪了依赖关系。

创建一个名为app.py 的文件并添加下面的代码片段。

from flask import Flask
from datetime import datetime
app = Flask(__name__)

data = {
    "drinks": [
        {
            "name": "Grape", 
            "description": "Delicious grape fruit drink",
            "date": datetime.now()
            },
            {
            "name": "Lemon", 
            "description": "Undiluted lemon fruit drink",
            "date": datetime.now()
            },
            {
            "name": "Mango", 
            "description": "This is a mango fruit",
            "date": datetime.now()
            }
        }
    ]
} 

@app.route("/")
def index():
        return "Welcome To My Drinks API"

@app.route('/drinks')
def get_drinks():
    return data


if __name__ == "__main__":
    app.debug = True
    app.run()

现在用终端中的命令python app.py ,启动服务器。打开你的浏览器到根域,确认欢迎页面。你也可以路由到/drinks ,获得API 的数据。

CI和CD管线架构

持续集成服务器要触发自动构建测试工作。这是为了检查推送的代码是否可靠。如果代码是可靠的,它将被集成、构建,并被发送到部署服务器。成功的通知也会被发送,被称为automation

如果不是,推送的代码将无法构建,并将发送另一个通知。这样,开发人员就可以修复错误,然后重新提交代码。然后持续集成工具将再次开始构建代码。这就是为什么持续集成和部署阶段仍然被认为是一个waterfall 的模式。

用Github Actions进行持续集成和部署

只要有推送到代码库的情况,Github Actions就会自动构建过程。这有助于减少手工构建作业的问题,如果构建没有完成,总是会通知。

这遵循了一个使用不同语言包文件的工作流程。早些时候,我们克隆了一个用Flask框架构建的Python应用程序。因此,我们要定义的工作流将是针对Python包的。

导航到资源库,点击action 链接。然后你应该收到类似于下图的东西。

Python Package

现在选择Publish Python Package 并点击Set up this workflow 。然后你将被转到python-publish.yml 编辑页面。粘贴下面的工作流程,并在编辑器内点击start commit

name: Python Package

on:
    push:
      branches: [ master ]

jobs:
    deploy:
       runs-on: ubuntu-latest
       strategy:
         fail-fast: false
         matrix:
            python-version: [3.8]
       steps:
        - uses: actions/checkout@master
        - name: Initialize Python 3.7
          uses: actions/setup-python@v1
          with:
            python-version: ${{matrix.python-version}}
        - name: Install dependencies
          run: |
            python -m pip install --upgrade pip
            pip install -r requirements.txt            

为Github行动定义的每个工作流程包都有三个主要属性。它们是:name,onjobs 。名称定义了给整个流程的标签,只要是有意义的,都可以是。

on 属性描述了自动化的开始时间。根据上述工作流程,在每次代码推送到版本库时,行动将开始构建代码,然后进入下一个步骤。

现在,jobs ,就是每一步要做的事情。在这个工作流程中,我们想在ubuntu-latest 机器上进行部署。部署代码需要按照定义的步骤进行。这一步将从安装一些描述的依赖关系开始,在成功构建后,你将有所有的步骤标记。类似下面的图片。

Successful Build

Docker镜像和容器基础知识

在过去,部署应用程序的默认方式是启动一个virtual machine 。这将复制必要的二进制文件的工件,并在后台执行。

从本质上讲,虚拟机是由一个安装了默认包集的主机操作系统组成的。应用程序将使用操作系统的文件和资源来成功运行。

此外,虚拟机通过hypervisor 。这个管理程序允许许多虚拟机运行,也被用来在操作系统上创建。

然而,权衡利弊的是操作系统的复制。虚拟机运行得越多,在主机操作系统中消耗的空间就越大。为了优化这一概念的积压,业界引入了应用程序的容器化。

容器是一种轻量级和可靠的技术,向消费者提供产品,同时更好地利用可用资源。

我们可以有一个运行多个容器的主机系统,而不是有多个虚拟机。容器中的进程是隔离的,它们可以通过主机操作系统上的包访问文件系统。

容器的创建和执行被委托给一个容器管理工具,如Docker 。这种操作系统级的虚拟化释放了通过使用容器运行多个应用程序的好处。

下面一节将介绍使用Docker和Dockerfile 的依赖性对应用程序进行容器化。

在项目文件夹内创建一个Dockerfile ,并添加下面的Docker命令。

FROM python:3.8
WORKDIR /app
COPY . .
RUN pip install -r requirements.txt
ENV PORT=80

此外,我们要构建Docker镜像,并将其推送到Docker中心进行存储。但在此之前,在Docker集线器中创建一个新的存储库,它将存储你的Docker镜像的构建动作。

你将把你的Docker hub账户细节添加到GitHub的秘密中。你可以通过进入你的GitHub账户,点击settings 按钮,然后点选secrets

在名称和值中添加以下内容。

DOCKER_USERNAME: <your-username>
DOCKER_PASSWORD: <your-password>
DOCKERHUB_REPO: <your-username>/<your-repository>

完成上述所有步骤后,导航到应用程序的Github仓库,用下面的代码编辑工作流程。这将构建Docker镜像并将其发送到你的Docker中心仓库。

name: Python Package

on:
    push:
      branches: [ master ]

jobs:
    deploy:
       runs-on: ubuntu-latest
       strategy:
         fail-fast: false
         matrix:
            python-version: [3.8]
       steps:
        - uses: actions/checkout@master
        - name: Initialize Python 3.8
          uses: actions/setup-python@v1
          with:
            python-version: ${{matrix.python-version}}
        - name: Install dependencies
          run: |
            python -m pip install --upgrade pip
            pip install -r requirements.txt            
        - name: Check docker installed or not
          run: docker run hello-world
        - name: Push to docker hub
          uses: docker/build-push-action/@v1
          with:
            username: ${{secrets.DOCKER_USERNAME}}
            password: ${{secrets.DOCKER_PASSWORD}}
            repository: ${{secrets.DOCKERHUB_REPO}}
            tag_with_ref: true

成功构建Docker镜像后,屏幕上将显示以下内容。

Successful Docker image Build

总结

在本教程中,我们看到了DevOps的概述,并建立了一个自动化管道。然后,开发了一个简单的Flask应用程序,并将其与Github行动持续集成。

我们通过这些Github动作来构建它的Docker镜像,然后将它推送到Docker中心进行适当的存储。