GitOps平台搭建及实践总结

发布日期: 2022-06-30     阅读: 3141    点赞: 0

一、认识DevOps

什么是DevOps?

从字面上来看,"DevOps"一词是由英文 Development(开发)和 Operations (运维)组合而成,但它所代表的理念和实践要比这广阔的多。DevOps 涵盖了安全、协作方式、数据分析等许多方面。那它是什么呢?

DevOps 强调通过一系列手段来实现既快又稳的工作流程,使每个想法(比如一个新的软件功能,一个功能增强请求或者一个 bug 修复)在从开发到生产环境部署的整个流程中,都能不断地为用户带来价值。这种方式需要开发团队和运维团队密切交流、高效协作并且彼此体谅。此外,DevOps 还要能够方便扩展,灵活部署。有了 DevOps,需求最迫切的工作就能通过自助服务和自动化得到解决;通常在IDE编写代码的开发人员也可与 IT 运维人员紧密合作,加速软件的构建、测试和发布,同时保障开发成果的稳定可靠。

当然,这意味着更改代码会更频繁,基础架构的使用也会更灵活。所以传统的管理策略无法满足这种需求。企业IT组织也需要应势而变,赢得先机。

DevOps与容器

DevOps 可以加快一个想法从提出到部署的整个过程。DevOps 的核心在于,在应用的整个生命周期中,都要确保日常运维任务自动化和环境的标准化。容器可以提供标准化的环境,需要一个平台来管理它们,同时提供内置的自动化功能并支持各种基础架构。

DevOps文化

DevOps 十分依赖协作文化,需要与开源和敏捷开发方法协同一致。

长期以来开源项目的文化一直被视作为构建 DevOps 文化的范本。[自由共享信息]是开源社区默认的协作之道。它有助于实施一系列文化变革,比如提高决策透明度、鼓励实验,战胜对失败的恐惧,或者实施奖励制度,鼓励彼此信任和协作。越来越多的企业/组织在数字化转型中采取此类行动,落地DevOps文化。

有了正确的领导和激励计划,开发和运维团队将能更好地促进开放文化。当整个公司都贯行了这种文化,DevOps 也就实现最佳成效。虽然 DevOps 字面上指的是开发和运维,但它需要每一个人的参与。

DevOps 流程

现代应用程序的开发流程不同于以往。许多团队都开始采用敏捷软件开发方法。在他们看来,DevOps 并不是什么新概念。事实上,"持续不断地尽早交付软件以满足客户需要"是《敏捷宣言》12 大原则中第一条原则。这就是为什么持续集成和持续部署(CI/CD)对 DevOps 团队至关重要。

但仅仅改变开发和运维流程还不够。您还需要系统化思考,找到办法真正地优化软件交付方式。也就是说,DevOps 既会为需要开发工作的业务部门带来改变,也会让支持终端用户的团队进行革新。关键是从终端用户到业务的持续反馈周期。

您的流程需要改变的不仅仅是工作方式。您的工作内容也不可避免地会发生变化。DevOps 不仅是为了加速创建原来的单体式应用,还要创建更适合这种持续交付节奏的新软件。

因此,DevOps 团队经常会使用[微服务架构]来构建软件,并通过 [API] 将这些服务彼此相连。通过构建较小的功能单元,开发团队就可以加速交付。因此,您必须关注如何管理这些服务和 API,并制定敏捷集成等策略,让它们能够协同工作。

这样的变革需要付出大量努力,但有了合适的技术,就可以马上开始。自动化能够加快流程,并最终帮助你将 DevOps 工作负载迁移至云上。IDC 的一项研究表明,85% 的 IT 领导者认为自动化对于其 DevOps 战略至关重要。这是因为自动化使基础架构能够承受 DevOps 带来的代码频繁更改,并让环境能够轻松地连续扩展。自动化可以解决重复繁琐的日常任务,让企业/组织的 IT 精英将精力投入到更重要的工作上。

需要DevOps专家帮助组织开发所需的实践、工具和文化,以便更有效地现代化改造现有应用并构建新的应用。

DevOps 平台和工具

选择能为流程提供支持的工具,对于 DevOps 的成功至关重要。运维团队要跟上快速开发周期,就需要利用高度灵活的平台,并像开发团队对待代码一样,对待平台的基础架构。手动部署不仅速度慢,而且可能出错。

因此,需要通过自动化来简化平台和应用的部署。

容器可以方便地在开发、测试和生产环境之间迁移应用。开发人员可以利用容器打包并隔离应用及其运行所需的一切,包括应用程序文件、运行时环境、依赖库和配置。

DevOps与Kubernetes

DevOps 方法加上容器,可为企业/组织提供云原生开发所需的底层技术。容器支持集开发、交付、集成和自动化于一体的统一环境。

而 Kubernetes 是实现容器操作自动化的现代方法。通过Kubernetes可轻松高效地管理在公共云、私有云或混合云中运行容器集群。

选择容器的可靠平台,可以保障顺利可靠的扩展和自动化。选择好合适的平台后,就可以充分利用已经实施的基础设施来进行文化和流程的优化或变革。

DevOps通过持续部署来实现扩展

持续集成和持续部署(CI/CD)是实施 DevOps 的一大重要成果。CI/CD 可帮助组织/企业频繁地向客户交付应用并检验软件质量,而且只需极少的人工干预。

具体而言,CI/CD 在整个应用生命周期内(从集成和测试阶段,到交付和部署)都引入了持续自动化和持续监控,让您能够快速识别和改正问题与缺陷。这些彼此关联的实践通常被统称为CI/CD流水线,需要开发和运维团队以敏捷方式协同支持。

二、GitOps简介

什么是 GitOps?

GitOps 是一套使用 Git 来管理基础架构和应用配置的实践,而 Git 指的是一个开源版控制系统。GitOps 在运行过程中以 Git 为声明性基础架构和应用的单一事实来源。

GitOps 使用 Git 拉取请求来自动管理基础架构的置备和部署。Git 存储库包含系统的全部状态,因此系统状态的修改痕迹既可查看也可审计。

GitOps 围绕开发者经验而构建,可帮助团队使用与软件开发相同的工具和流程来管理基础架构。除了 Git 以外,GitOps 还支持您按照自己的需求选择工具。

引入GitOps

通常要使用 GitOps,需要有支持声明式管理的基础架构(基础架构即代码)。正因为如此,GitOps 经常被用作 Kubernetes和云原生应用开发的运维模式,并且可以实现对 Kubernetes 的持续部署。

GitOps 可用于构建开发流程、对应用进行编码、管理配置、推送容器镜像到镜像仓库、以及在 Kubernetes上进行部署。

什么是 GitOps 工作流?

GitOps通常 、被认为是基础架构即代码(IaC) 的一个演变,以 Git 为基础架构配置的版本控制系统。IaC 通常采用声明式方法来管理基础架构,定义系统的期望状态,并跟踪系统的实际状态。

与 IaC 一样,GitOps 也要求通过声明式描述系统的期望状态。通过使用声明式工具,您所有的配置文件和源代码都可以在 Git 中进行版本控制。

CI/CD 流程通常由外部事件触发,比如代码被推送到了存储库中。在 GitOps 工作流中,要进行变更,需要通过拉取请求来修改 Git 仓库的状态。

使用拉取请求和 Git 之类的版本控制系统让部署过程清晰可见。这样一来,您便可查看和跟踪对系统进行的任何变更,提供审计跟踪,并在出现问题时进行回滚变更。

GitOps 工作流可以提高生产率,加快开发和部署速度,同时提高系统的稳定性和可靠性。

GitOps 与 DevOps 之间有何区别?

GitOps 和 DevOps 在原则和目标上有着相同之处。DevOps 侧重于文化转变,为开发团队和运维团队提供了一种协同工作方式。

GitOps 则为您提供工具和框架来落地 DevOps,如协作、CI/CD 和版本控制,并将其应用于基础架构自动化和应用部署。

开发人员可以在自己已经熟悉的代码存储库中作业,而运维部门则可以将其他必要组件落实到位。

三、基于Gitlab、Jenkins搭建GitOps平台及流水线实践

Gitlab安装

Jenkins安装

以Docker方式安装Jenkins

1. 部署方案简介

  • Docker架构

docker架构

  • Jenkins部署图

    jenkins部署图

2. 安装docker

省略

3. 构建自定义镜像

基于Jenkins官方镜像构建自定义镜像,安装aws cli

FROM jenkins/jenkins:2.356-jdk11
USER root
RUN apt-get update && apt-get install -y lsb-release
RUN curl -fsSLo /usr/share/keyrings/docker-archive-keyring.asc \
  https://download.docker.com/linux/debian/gpg
RUN echo "deb [arch=$(dpkg --print-architecture) \
  signed-by=/usr/share/keyrings/docker-archive-keyring.asc] \
  https://download.docker.com/linux/debian \
  $(lsb_release -cs) stable" > /etc/apt/sources.list.d/docker.list
RUN apt-get update && apt-get install -y docker-ce-cli python3 python3-pip && rm -rf /var/lib/apt/lists/*
RUN pip3 install --no-cache --upgrade pip setuptools -i https://pypi.tuna.tsinghua.edu.cn/simple
RUN pip install awscli -i https://pypi.tuna.tsinghua.edu.cn/simple
USER jenkins
RUN jenkins-plugin-cli --plugins "blueocean:1.25.5 docker-workflow:1.28"

构建命令

docker build -t jenkins:jenkins:2.356-jdk11-aws .

4. 创建桥接网络

docker network create jenkins

5. 部署docker:dind (docker in docker).

该步骤主要是为了在Jenkins节点中能够执行docker命令

docker run \
  --name jenkins-docker \
  --detach \
  --privileged \
  --network jenkins \
  --network-alias docker \
  --env DOCKER_TLS_CERTDIR=/certs \
  --volume jenkins-docker-certs:/certs/client \
  --volume jenkins-data:/var/jenkins_home \
  --publish 2376:2376 \
  docker:dind \
  --storage-driver overlay2

6. 部署Jenkins blueocean

docker run \
  --name jenkins-blueocean \
  --restart=on-failure \
  --detach \
  --network jenkins \
  --env DOCKER_HOST=tcp://docker:2376 \
  --env DOCKER_CERT_PATH=/certs/client \
  --env DOCKER_TLS_VERIFY=1 \
  --publish 8080:8080 \
  --publish 50000:50000 \
  --volume jenkins-data:/var/jenkins_home \
  --volume jenkins-docker-certs:/certs/client:ro \
  jenkins:jenkins:2.356-jdk11-aws

GitOps流水线

1. Java Maven工程自动构建、打包、部署

以SysAPP开发环境流水线为例:

pipeline {
    agent any
    post {
      failure {
        updateGitlabCommitStatus name: 'build', state: 'failed'
      }
      success {
        updateGitlabCommitStatus name: 'build', state: 'success'
      }
    }
    options {
      gitLabConnection('gitlab')
    }
    triggers {
        gitlab(triggerOnPush: true, triggerOnMergeRequest: true, branchFilterType: 'All')
    }
    environment {
        AWS_ACCESS_KEY_ID     = credentials('aws-ak')
        AWS_SECRET_ACCESS_KEY = credentials('aws-sk')
    }
    stages {
        stage('Build') {
            agent {
                docker {
                    image 'maven:3.8.6-openjdk-8-slim'
                    args '-v $HOME/.m2:/root/.m2:z -u root'
                    reuseNode true
                }

            }
            steps {
                sh 'echo $HOME'
                sh 'mvn clean install -DskipTests=true -Dmaven.javadoc.skip=true -U -B -V'
            }
        }

        stage('Build docker image') {
            steps {
                script {
                    dockerImage = docker.build "1234555.dkr.ecr.cn-northwest-1.amazonaws.com.cn/app:dev"
                }
            }
        }

        stage('Login AWS ECR') {
            steps {
                sh "aws ecr get-login-password --region cn-northwest-1 | docker login --username AWS --password-stdin 123456.dkr.ecr.cn-northwest-1.amazonaws.com.cn"
            }
        }

        stage('Push image to ECR') {
            steps {
                sh "docker push 123456.dkr.ecr.cn-northwest-1.amazonaws.com.cn/app:dev"
            }
        }
        stage('Deploy') {
            steps {
                sshagent (credentials: ['backend-dev-ec2']) {
                    sh 'ssh -o StrictHostKeyChecking=no -l ec2-user hostname "cd docker_deploy/app && sh ./pull_image.sh && sh ./kill.sh && sh ./start.sh"'
                }
            }
        }
    }
}

2. Vue前端应用构建、打包、部署

pipeline {
    agent any
    post {
      failure {
        updateGitlabCommitStatus name: 'build', state: 'failed'
      }
      success {
        updateGitlabCommitStatus name: 'build', state: 'success'
      }
    }
    options {
      gitLabConnection('gitlab')
    }
    triggers {
        gitlab(triggerOnPush: true, triggerOnMergeRequest: true, branchFilterType: 'All')
    }
    environment {
        AWS_ACCESS_KEY_ID     = credentials('aws-ak')
        AWS_SECRET_ACCESS_KEY = credentials('aws-sk')
    }
    stages {
        stage('Build') {
            agent {
                docker {
                    image 'node:14'
                    reuseNode true
                }

            }
            steps {
                sh 'npm install'
                sh 'npm run build:dev'
                sh 'ls -al .'
            }
        }

        stage('Build docker image') {
            steps {
                sh 'ls -al .'
                script {
                    dockerImage = docker.build "123456.dkr.ecr.cn-northwest-1.amazonaws.com.cn/management:dev"
                }
            }
        }

        stage('Login AWS ECR') {
            steps {
                sh "aws ecr get-login-password --region cn-northwest-1 | docker login --username AWS --password-stdin 850054557990.dkr.ecr.cn-northwest-1.amazonaws.com.cn"
            }
        }

        stage('Push image to ECR') {
            steps {
                sh "docker push 123456.dkr.ecr.cn-northwest-1.amazonaws.com.cn/management:dev"
            }
        }
        stage('Deploy') {
            steps {
                sshagent (credentials: ['frontend-dev-ec2']) {
                    sh 'ssh -o StrictHostKeyChecking=no -l ec2-user hostname "cd docker_deploy/management && sh ./update.sh"'
                }
            }
        }
    }
}


四、基于gitea、drone的GitOps平台搭建及流水线实践

Gitea安装

安装Drone

安装API Server

docker run \
  --volume=/data/drone:/data \
  --env=DRONE_GITLAB_SERVER=http://10.28.24.205:9999 \
  --env=DRONE_GITLAB_CLIENT_ID=8059e29c3239abf1efb25c036c3a279b53584d492d1f894e28aefa5e4070bd04 \
  --env=DRONE_GITLAB_CLIENT_SECRET=28960f9a9f010dc93152e0fdf1555a79b21a90d0768c6b4e6eae44e9ba69ced3 \
  --env=DRONE_RPC_SECRET=03fd0a08827228406737a00b1eb94d35 \
  --env=DRONE_SERVER_HOST=10.28.24.205:8000 \
  --env=DRONE_SERVER_PROTO=http \
  --env=DRONE_USER_CREATE=username:admin:true \
  --publish=8000:80 \
  --publish=443:443 \
  --restart=always \
  --detach=true \
  --name=drone \
  drone/drone:2

安装Runner

docker run --detach \
  --volume=/var/run/docker.sock:/var/run/docker.sock \
  --env=DRONE_RPC_PROTO=http \
  --env=DRONE_RPC_HOST=10.28.24.209:8000 \
  --env=DRONE_RPC_SECRET=03fd0a08827228406737a00b1eb94d35 \
  --env=DRONE_RUNNER_CAPACITY=2 \
  --env=DRONE_RUNNER_NAME=runner-1 \
  --publish=3000:3000 \
  --restart=always \
  --name=runner \
  drone/drone-runner-docker:1

Java maven工程流水线

kind: pipeline
name: default
steps:
  - name: build
    image: maven:3-jdk-11
    volumes:
    - name: maven-cache
      path: /root/.m2
    commands:
      - ls -al ~/.
      - mvn install -DskipTests=true -Dmaven.javadoc.skip=true -B -V
  - name: docker
    image: ubase/docker:awscli
    environment:
      AWS_ACCESS_KEY_ID:
        from_secret: aws_ak
      AWS_SECRET_ACCESS_KEY:
        from_secret: aws_sk
      AWS_DEFAULT_REGION:
        from_secret: aws_region
    volumes:
      - name: dockersock
        path: /var/run/docker.sock
    commands:
      - docker build -t 123456.dkr.ecr.cn-northwest-1.amazonaws.com.cn/app:dev .
      - aws ecr get-login-password --region cn-northwest-1 | docker login --username AWS --password-stdin 850054557990.dkr.ecr.cn-northwest-1.amazonaws.com.cn
      - docker push 123456.dkr.ecr.cn-northwest-1.amazonaws.com.cn/app:dev
  - name: notify
    image: drillster/drone-email
    settings:
      from: support<dev_support@gmail.com>
      host: smtp.feishu.cn
      port: 465
      username:
        from_secret: email_username
      password:
        from_secret: email_password
      recipients:
        - user@gmail.com
volumes:
  - name: maven-cache
    host:
      path: /var/lib/cache
  - name: dockersock
    host:
      path: /var/run/docker.sock