• GitLab 持续集成


    原文链接:https://mp.weixin.qq.com/s/yP9kiCwKcg_VYkI4Qjk2Yw

    互联网软件的开发和发布,已经形成了一套标准流程,最重要的组成部分就是持续集成(Continuous integration,简称CI)。

    持续集成

    持续集成指的是,频繁地(一天多次)将代码集成到主干。它的好处主要有两个:

    • 快速发现错误。每完成一点更新,就集成到主干,可以快速发现错误,定位错误也比较容易。

    • 防止分支大幅偏离主干。如果不是经常集成,主干又在不断更新,会导致以后集成的难度变大,甚至难以集成。

    Martin Fowler 说过,"持续集成并不能消除 Bug,而是让它们非常容易发现和改正。"

    持续集成

    持续集成强调开发人员提交了新代码之后,立刻进行构建、(单元)测试。根据测试结果,我们可以确定新代码和原有代码能否正确地集成在一起。

    与持续集成相关的,还有两个概念,分别是持续交付和持续部署。

    持续交付

    持续交付(Continuous delivery)指的是,频繁地将软件的新版本,交付给质量团队或者用户,以供评审。如果评审通过,代码就进入生产阶段。

    持续交付可以看作持续集成的下一步。它强调的是,不管怎么更新,软件是随时随地可以交付的。

    持续交付

    持续交付在持续集成的基础上,将集成后的代码部署到更贴近真实运行环境的「类生产环境」(production-like environments)中。比如,我们完成单元测试后,可以把代码部署到连接数据库的 Staging 环境中更多的测试。如果代码没有问题,可以继续手动部署到生产环境中。

    持续部署

    持续部署(continuous deployment)是持续交付的下一步,指的是代码通过评审以后,自动部署到生产环境。

    持续部署的目标是,代码在任何时刻都是可部署的,可以进入生产阶段。

    持续部署的前提是能自动化完成测试、构建、部署等步骤。

    持续部署

    持续集成的操作流程

    根据持续集成的设计,代码从提交到生产,整个过程有以下几步。

    提交

    流程的第一步,是开发者向代码仓库提交代码。所有后面的步骤都始于本地代码的一次提交(commit)。

    测试(第一轮)

    代码仓库对 commit 操作配置了钩子(hook),只要提交代码或者合并进主干,就会跑自动化测试。

    测试的种类:

    • 单元测试:针对函数或模块的测试

    • 集成测试:针对整体产品的某个功能的测试,又称功能测试

    • 端对端测试:从用户界面直达数据库的全链路测试

    第一轮至少要跑单元测试。

    构建

    通过第一轮测试,代码就可以合并进主干,就算可以交付了。

    交付后,就先进行构建(build),再进入第二轮测试。所谓构建,指的是将源码转换为可以运行的实际代码,比如安装依赖,配置各种资源(样式表、JS脚本、图片)等等。

    常用的构建工具如下:

    • Jenkins

    • Travis

    • Codeship

    • Strider

    Jenkins 和 Strider 是开源软件,Travis 和 Codeship 对于开源项目可以免费使用。它们都会将构建和测试,在一次运行中执行完成。

    测试(第二轮)

    构建完成,就要进行第二轮测试。如果第一轮已经涵盖了所有测试内容,第二轮可以省略,当然,这时构建步骤也要移到第一轮测试前面。

    第二轮是全面测试,单元测试和集成测试都会跑,有条件的话,也要做端对端测试。所有测试以自动化为主,少数无法自动化的测试用例,就要人工跑。

    需要强调的是,新版本的每一个更新点都必须测试到。如果测试的覆盖率不高,进入后面的部署阶段后,很可能会出现严重的问题。

    部署

    通过了第二轮测试,当前代码就是一个可以直接部署的版本(artifact)。将这个版本的所有文件打包( tar filename.tar * )存档,发到生产服务器。

    生产服务器将打包文件,解包成本地的一个目录,再将运行路径的符号链接(symlink)指向这个目录,然后重新启动应用。这方面的部署工具有Ansible,Chef,Puppet等。

    回滚

    一旦当前版本发生问题,就要回滚到上一个版本的构建结果。最简单的做法就是修改一下符号链接,指向上一个版本的目录。

    使用 GitLab 持续集成

    从 GitLab 8.0 开始,GitLab CI 就已经集成在 GitLab 中,我们只要在项目中添加一个.gitlab-ci.yml文件,然后添加一个 Runner,即可进行持续集成。而且随着 GitLab 的升级,GitLab CI 变得越来越强大。

    概念

    Pipeline

    一次 Pipeline 其实相当于一次构建任务,里面可以包含多个流程,如安装依赖、运行测试、编译、部署测试服务器、部署生产服务器等流程。

    任何提交或者 Merge Request 的合并都可以触发 Pipeline,如下图所示:

    +------------------+           +----------------+
    | | trigger | |
    | Commit / MR +---------->+ Pipeline |
    | | | |
    +------------------+ +----------------+
    Stages

    Stages 表示构建阶段,说白了就是上面提到的流程。我们可以在一次 Pipeline 中定义多个 Stages,这些 Stages 会有以下特点:

    • 所有 Stages 会按照顺序运行,即当一个 Stage 完成后,下一个 Stage 才会开始

    • 只有当所有 Stages 完成后,该构建任务 (Pipeline) 才会成功

    • 如果任何一个 Stage 失败,那么后面的 Stages 不会执行,该构建任务 (Pipeline) 失败

    因此,Stages 和 Pipeline 的关系就是:

    +--------------------------------------------------------+
    | |
    | Pipeline |
    | |
    | +-----------+ +------------+ +------------+ |
    | | Stage 1 |---->| Stage 2 |----->| Stage 3 | |
    | +-----------+ +------------+ +------------+ |
    | |
    +--------------------------------------------------------+
    Jobs

    Jobs 表示构建工作,表示某个 Stage 里面执行的工作。我们可以在 Stages 里面定义多个 Jobs,这些 Jobs 会有以下特点:

    • 相同 Stage 中的 Jobs 会并行执行

    • 相同 Stage 中的 Jobs 都执行成功时,该 Stage 才会成功

    • 如果任何一个 Job 失败,那么该 Stage 失败,即该构建任务 (Pipeline) 失败

    所以,Jobs 和 Stage 的关系图就是:

    +------------------------------------------+
    | |
    | Stage 1 |
    | |
    | +---------+ +---------+ +---------+ |
    | | Job 1 | | Job 2 | | Job 3 | |
    | +---------+ +---------+ +---------+ |
    | |
    +------------------------------------------+

    基于 Docker 安装 GitLab Runner

    GitLab Runner 简介

    理解了上面的基本概念之后,有没有觉得少了些什么东西 —— 由谁来执行这些构建任务呢?

    答案就是 GitLab Runner 了!

    想问为什么不是 GitLab CI 来运行那些构建任务?

    一般来说,构建任务都会占用很多的系统资源 (譬如编译代码),而 GitLab CI 又是 GitLab 的一部分,如果由 GitLab CI 来运行构建任务的话,在执行构建任务的时候,GitLab 的性能会大幅下降。

    GitLab CI 最大的作用是管理各个项目的构建状态,因此,运行构建任务这种浪费资源的事情就交给 GitLab Runner 来做拉!

    因为 GitLab Runner 可以安装到不同的机器上,所以在构建任务运行期间并不会影响到 GitLab 的性能

    基于 Docker 安装 GitLab Runner

    准备目录结构

    目录结构

    docker-compose.yml

    version: '2'
    services:
    gitlab:
    image: twang2218/gitlab-ce-zh:10.5
    restart: always
    hostname: '10.3.50.160'
    container_name: gitlab
    environment:
    TZ: 'Asia/Shanghai'
    GITLAB_OMNIBUS_CONFIG: |
    external_url 'http://10.3.50.160:8080'
    gitlab_rails['gitlab_shell_ssh_port'] = 2222
    unicorn['port'] = 8888
    nginx['listen_port'] = 8080
    ports:
    - '8080:8080'
    - '8443:443'
    - '2222:22'
    volumes:
    - /etc/localtime:/etc/localtime
    - ./conf:/etc/gitlab
    - ./data/logs:/var/log/gitlab
    - ./data/data:/var/opt/gitlab
    gitlab-runner:
    image: gitlab/gitlab-runner
    restart: always
    hostname: gitlab-runner
    container_name: gitlab-runner
    extra_hosts:
    - git.imlcs.top:10.3.50.160
    depends_on:
    - gitlab
    volumes:
    - /etc/localtime:/etc/localtime
    - ./runner:/etc/gitlab-runner
    - /var/run/docker.sock:/var/run/docker.sock

    GitLab CI 地址与令牌参数

    项目–>设置–>CI/CD–>Runner 设置

    查找位置

    注册 Runner

    方法一

    docker exec -it gitlab-runner  gitlab-runner register -n 
    --url http://10.3.50.160:8080/
    --registration-token cpR4sgBCsZ-TJUpJVz9t
    --description "dockersock"
    --docker-privileged=true
    --docker-pull-policy="if-not-present"
    --docker-image "docker:latest"
    --docker-volumes /var/run/docker.sock:/var/run/docker.sock
    --docker-volumes /root/m2:/root/.m2
    --executor docker

    方法二

    docker exec -it gitlab-runner gitlab-runner register
    # 输入 GitLab 地址
    Please enter the gitlab-ci coordinator URL (e.g. https://gitlab.com/):
    http://10.3.50.160:8888/
    # 输入 GitLab Token
    Please enter the gitlab-ci token for this runner:
    1Lxq_f1NRfCfeNbE5WRh
    # 输入 Runner 的说明
    Please enter the gitlab-ci description for this runner:
    可以为空
    # 设置 Tag,可以用于指定在构建规定的 tag 时触发 ci
    Please enter the gitlab-ci tags for this runner (comma separated):
    deploy
    # 这里选择 true ,可以用于代码上传后直接执行
    Whether to run untagged builds [true/false]:
    true
    # 这里选择 false,可以直接回车,默认为 false
    Whether to lock Runner to current project [true/false]:
    false
    # 选择 runner 执行器,这里我们选择的是 shell
    Please enter the executor: virtualbox, docker+machine, parallels, shell, ssh, docker-ssh+machine, kubernetes, docker, docker-ssh:
    #shell
    docker # 使用 docker 作为输出模式
    Please enter the default Docker image (e.g. ruby:2.1):
    alpine:latest # 使用的基础镜像

    使用 Runner

    .gitlab-ci.yml

    在项目工程下编写.gitlab-ci.yml配置文件:

    示例一,找一个springboot的简单项目

    image: docker-maven:alpine
    services:
    - redis:3-alpine
    #Maven 阿里云镜像
    #before_script:
    # - echo -e "<?xml version=""1.0"" encoding=""UTF-8""?><settings xmlns=""http://maven.apache.org/SETTINGS/1.0.0"" xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xsi:schemaLocation=""http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd""><mirrors><mirror><id>alimaven</id><name>aliyun maven</name><url>http://maven.aliyun.com/nexus/content/groups/public/</url><mirrorOf>central</mirrorOf></mirror></mirrors></settings>" > ~/.m2/settings.xml
    # 定义 stages
    stages:
    # - test
    - build
    # 定义 jobs
    #test app:
    # stage: test
    # script:
    # - echo "I am test job"
    # - mvn test
    # 定义 job
    build app:
    stage: build
    script:
    - mvn -Dmaven.test.skip=true clean package docker:build

    示例二

    stages:
    - install_deps
    - test
    - build
    - deploy_test
    - deploy_production
    cache:
    key: ${CI_BUILD_REF_NAME}
    paths:
    - node_modules/
    - dist/
    # 安装依赖
    install_deps:
    stage: install_deps
    only:
    - develop
    - master
    script:
    - npm install
    # 运行测试用例
    test:
    stage: test
    only:
    - develop
    - master
    script:
    - npm run test
    # 编译
    build:
    stage: build
    only:
    - develop
    - master
    script:
    - npm run clean
    - npm run build:client
    - npm run build:server
    # 部署测试服务器
    deploy_test:
    stage: deploy_test
    only:
    - develop
    script:
    - pm2 delete app || true
    - pm2 start app.js --name app
    # 部署生产服务器
    deploy_production:
    stage: deploy_production
    only:
    - master
    script:
    - bash scripts/deploy/deploy.sh

    上面的配置把一次 Pipeline 分成五个阶段:

    • 安装依赖(install_deps)

    • 运行测试(test)

    • 编译(build)

    • 部署测试服务器(deploy_test)

    • 部署生产服务器(deploy_production)

    注意:设置 Job.only 后,只有当 develop 分支和 master 分支有提交的时候才会触发相关的 Jobs。

    节点说明:

    • stages:定义构建阶段,这里只有一个阶段 deploy

    • deploy:构建阶段 deploy 的详细配置也就是任务配置

    • script:需要执行的 shell 脚本

    • only:这里的 master 指在提交到 master 时执行

    • tags:与注册 runner 时的 tag 匹配

    测试集成效果

    所有操作完成后 push 代码到服务器,查看是否成功:

     

    passed 表示执行成功

    其它命令

    • 删除注册信息

    gitlab-ci-multi-runner unregister --name "名称"
    • 查看注册列表

    gitlab-ci-multi-runner list

    附:项目配置 Dockerfile 案例

    FROM openjdk:8-jre
    MAINTAINER Lusifer <topsale@vip.qq.com>
    ENV APP_VERSION 1.0.0-SNAPSHOT
    ENV DOCKERIZE_VERSION v0.6.1
    RUN wget https://github.com/jwilder/dockerize/releases/download/$DOCKERIZE_VERSION/dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz
    && tar -C /usr/local/bin -xzvf dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz
    && rm dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz
    RUN mkdir /app
    COPY myshop-service-user-provider-$APP_VERSION.jar /app/app.jar
    ENTRYPOINT ["dockerize", "-timeout", "5m", "-wait", "tcp://192.168.10.131:3306", "java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "/app/app.jar"]
    EXPOSE 8501

    持续集成实战用户管理服务

    部署通用模块项目

    先将所有被依赖项目(通用模块项目)部署到 Nexus,为项目创建一个deploy.bat文件,示例代码如下:

    cd ..
    cd myshop-dependencies
    call mvn deploy
    cd ..
    cd myshop-commons
    call mvn deploy
    cd ..
    cd myshop-commons-domain
    call mvn deploy
    cd ..
    cd myshop-commons-mapper
    call mvn deploy
    cd ..
    cd myshop-commons-dubbo
    call mvn deploy
    cd ..
    cd myshop-static-backend
    call mvn deploy
    cd ..
    cd myshop-service-user-api
    call mvn deploy

    持续集成依赖管理项目

    由于我们所有项目的父工程都是依赖于myshop-dependencies,所以我们持续集成的第一步是将该项目进行持续集成,在项目目录创建.gitlab-ci.yml文件,代码如下:

    stages:
    - deploy
    deploy:
    stage: deploy
    script:
    - /usr/local/maven/apache-maven-3.5.3/bin/mvn clean install

    持续集成服务提供者

    gitlab-ci.yml

    # 定义阶段
    stages:
    - build
    - push
    - run
    - clean
    build:
    stage: build
    script:
    - /usr/local/maven/apache-maven-3.5.3/bin/mvn clean package
    - cp target/myshop-service-user-provider-1.0.0-SNAPSHOT.jar docker
    - cd docker
    - docker build -t 192.168.10.133:5000/myshop-service-user-provider:v1.0.0 .
    push:
    stage: push
    script:
    - docker push 192.168.10.133:5000/myshop-service-user-provider:v1.0.0
    run:
    stage: run
    script:
    - cd docker
    - docker-compose down
    - docker-compose up -d
    clean:
    stage: clean
    script:
    - docker image prune -f

    Dockerfile

    FROM openjdk:8-jre
    MAINTAINER Lusifer <topsale@vip.qq.com>
    ENV APP_VERSION 1.0.0-SNAPSHOT
    ENV DOCKERIZE_VERSION v0.6.1
    RUN wget https://github.com/jwilder/dockerize/releases/download/$DOCKERIZE_VERSION/dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz
    && tar -C /usr/local/bin -xzvf dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz
    && rm dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz
    RUN mkdir /app
    COPY myshop-service-user-provider-$APP_VERSION.jar /app/app.jar
    ENTRYPOINT ["dockerize", "-timeout", "5m", "-wait", "tcp://192.168.10.131:3306", "java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "/app/app.jar"]
    EXPOSE 8501 22222 20881

    docker-compose.yml

    version: '3.1'
    services:
    myshop-service-user-provider:
    image: 192.168.10.133:5000/myshop-service-user-provider:v1.0.0
    container_name: myshop-service-user-provider
    ports:
    - 8501:8501
    - 22222:22222
    - 20881:20881
    networks:
    default:
    external:
    name: dubbo

    持续集成服务消费者

    gitlab-ci.yml

    stages:
    - build
    - push
    - run
    - clean
    build:
    stage: build
    script:
    - /usr/local/maven/apache-maven-3.5.3/bin/mvn clean package
    - cp target/myshop-service-user-consumer-1.0.0-SNAPSHOT.jar docker
    - cd docker
    - docker build -t 192.168.10.133:5000/myshop-service-user-consumer:v1.0.0 .
    push:
    stage: push
    script:
    - docker push 192.168.10.133:5000/myshop-service-user-consumer:v1.0.0
    run:
    stage: run
    script:
    - cd docker
    - docker-compose down
    - docker-compose up -d
    clean:
    stage: clean
    script:
    - docker image prune -f

    Dockerfile

    FROM openjdk:8-jre
    MAINTAINER Lusifer <topsale@vip.qq.com>
    ENV APP_VERSION 1.0.0-SNAPSHOT
    ENV DOCKERIZE_VERSION v0.6.1
    RUN wget https://github.com/jwilder/dockerize/releases/download/$DOCKERIZE_VERSION/dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz
    && tar -C /usr/local/bin -xzvf dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz
    && rm dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz
    RUN mkdir /app
    COPY myshop-service-user-consumer-$APP_VERSION.jar /app/app.jar
    ENTRYPOINT ["dockerize", "-timeout", "5m", "-wait", "tcp://192.168.10.131:20881", "java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "/app/app.jar"]
    EXPOSE 8601 8701

    docker-compose.yml

    version: '3.1'
    services:
    myshop-service-user-consumer:
    image: 192.168.10.133:5000/myshop-service-user-consumer:v1.0.0
    container_name: myshop-service-user-consumer
    ports:
    - 8601:8601
    - 8701:8701
    networks:
    default:
    external:
    name: my_net
  • 相关阅读:
    2019暑假集训 windy数
    2019暑假集训 数字游戏
    2019暑假集训 周年纪念晚会
    2019暑假集训 加分二叉树
    0013-求圆柱体体积
    0012-求滑动距离
    0011-绝对值函数
    0010-温度转换
    0009-乘法问题
    0008-三位数倒序问题
  • 原文地址:https://www.cnblogs.com/-wenli/p/13431579.html
Copyright © 2020-2023  润新知