转载

使用 Jenkins + Nginx 实现预发布

全部配置详见: https://github.com/xuexb/DevOps/tree/master/jenkins-nginx-stg

什么是预发布?在我看来和灰度发布、单台是一样的意思,大白话就是说从线上摘一个有流量的机器,上线时先上到该机器中,稳定运行后再全流量上线。

方案

1. cookie / 参数

在浏览器里写入一个特殊标识的 cookie 或者参数,在接入层根据标识来判断把流量落入到预发布机器(Nginx 反向代理)。

2. 白名单

在接入层根据入网 IP 来判断是否在名单内,再代理到不同的环境。

3. 绑定 Hosts 直连应用层

每个应用层都是一个独立的服务,由接入层做负载均衡(LBS),而客户端可以直接绑定应用层的 IP ,直连应用层。

其实以上方案大同小异,本篇文章以绑定 Hosts 直连应用层为例介绍。

访问流程

使用 Jenkins + Nginx 实现预发布

服务说明

这里都是以 Docker 运行对应的服务。

  • LBS proxy - 接入层,由一台 Nginx 做反向代理到应用层
  • Gogs - 一个简易的 Git Server ,主要一直用 GitLab 想换换口味。。。这里主要提供代码仓库的作用
  • Jenkins - 构建、发布
  • www-app - 虚拟出多个生产环境,这里只是一个 Nginx Web Server ,基于 dockerxman/docker-ubuntu-ssh 创建,主要为了做 SSH 免密码登录,这里只创建两个实例,会把第一个实例做为单台预发环境
  • user - 模拟用户环境,因为宿主网络和容器联通太麻烦,即使我用了 pipework 也大半天没折腾好,索性就使用一个 Centos 环境用来验证访问( curl

绑定 IP 说明

容器名 别名 IP 说明
www1 prd_www1 192.168.1.101 生产环境1
www2 prd_www2 192.168.1.102 生产环境2
proxy LBS 192.168.1.100 接入层
user - - 模拟用户环境,使用 docker exec -it user /bin/bash 进入,不用自定 IP
jenkins - - Jenkins 容器,在接入层反向代理到该容器
gogs - - Gogs 容器,在接入层反向代理到该容器

域名端口说明

需要宿主绑定 127.0.0.1 gogs.fe.com jenkins.fe.com Hosts

  • 宿主:80 - proxy 容器对宿主暴露的端口,可访问 Jenkins 、Gogs
  • www.fe.com - 接入层入口,在 user 容器中访问( curl
  • gogs.fe.com - Gogs 访问入口
  • jenkins.fe.com - Jenkins 访问入口

发布配置

把 www1 的环境做为预发布环境,使用 Jenkins Pipeline 脚本,在发布时直接发布到预发环境,并等待,在一定时间(比如1天)之内,如果在全量面板点击继续,则全量发布(其实就是同步到 www2 环境,因为一共就2台)。

使用 Jenkins + Nginx 实现预发布

Gogs 配置

  1. 启动后创建一个用户,并把公钥( env/id_rsa.pub )添加到帐户的 SSH 中,主要用于 Jenkins 中克隆 Gogs 项目授权
  2. 创建一个仓库,并添加一个产出目录( dist/ )和产出的一个测试文件( dist/index.html ),模拟编译之后的文件

Jenkins 配置

  1. 配置 Publish over SSH 插件,注意:
    • key - env/id_rsa 密钥
    • hostname - 容器的名称
    • 使用 Jenkins + Nginx 实现预发布
  2. 创建一个用于 Git 克隆的凭证
    • 使用 Jenkins + Nginx 实现预发布
  3. jenkinsfile
pipeline {
    agent any

    options {
        timestamps()
    }

    stages {
        stage('Clone code') {
            steps {
                git credentialsId: 'b94b24ac-b1d0-4e63-81f8-2f1d889bd475', url: 'git@gogs:xiaowu/webapp.git'
            }
        }

        stage('Run Build') {
            steps {
                echo '测试 build'
            }
        }

        stage('Deploy Pre-Release') {
            steps {
                sshPublisher(publishers: [sshPublisherDesc(configName: 'prd-1', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: 'nginx -v', execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '/app', remoteDirectorySDF: false, removePrefix: 'dist', sourceFiles: 'dist/*')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
            }
        }

        stage('Deploy All') {
            options {
                timeout(time: 3, unit: 'DAYS')
            }

            input {
                message '全量发布?'
                ok '发布'
            }

            steps {
                sshPublisher(publishers: [sshPublisherDesc(configName: 'prd-2', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: 'nginx -v', execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '/app', remoteDirectorySDF: false, removePrefix: 'dist', sourceFiles: 'dist/*')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
            }
        }
    }

    post {
        always {
            deleteDir()
        }
    }
}

验证

登录 user 容器去验证,其实就是模拟了用户终端,默认时绑定的 Hosts 为 192.168.1.100 www.fe.com 这是接入层,使用 curl www.fe.com 可以看到访问结果,当任务发布完成预发布时(在 Gogs 修改示例文件保存后,在 Jenkins 重新构建),构建会自动发布到预发布 www1 中,在 user 容器可以直接绑定 www1 的容器验证 192.168.1.101 www.fe.com ,验证通过后( curl www.fe.com )可以全量上线。

难点

1. 应用层应当具备独立的服务

每个应用层自身应该可以独立访问,由接入层代理,那么应用层 Nginx 就需要多绑定几个 server_name 了,如:

  • www.fe.com - 供直联应用层使用
  • prd_www* - 供接入层 upstream 配置

2. 需要给节点多配置执行者数量

因为等待中的任务也会占用节点执行者数量,如果少了多个并发任务可能就要凉凉。。。

其实这只是我对预发布、灰度发布、单台预发的一种探索,比如把测试、单台、全量拆成三个任务是否更合理?这就需要在实际项目中真实的应用并分析了。

接下来的目标:

  • 快速回滚
  • 应用 Docker 镜像发布
原文  https://xuexb.com/post/jenkins-nginx-pre-release.html
正文到此结束
Loading...