持续化集成与自动化部署

持续集成与自动化部署

  • 什么是持续集成?

Contiunous Integration (CI)

持续集成式一种软件开发实践,即团队开发成员经常集成她们呢的工作,通常每个成员至少集成一次,也就是意味着每天可能会发生多次的集成。每次集成都通过自动化的构建(包括编译、发布、自动化测试)来验证,从而尽快地发现集成错误,许多团队发现这个过程可以大大减少集成的问题,让团队能够更快的开发内聚的软件。

  • 没有持续集成 -> 导致?

1.浪费大量的时间:项目做模块集成的时候,发现很多借口都不通。
2.构建过程不透明:需要人手动去便宜打包最新的代码。
3.脚本乱飞:发布代码,上线,基本靠手动。

  • 持续集成的最佳实践

1.维护一个单一的代码库
2.使构建自动化
3.执行测试是构建的一部分
4.集成日志及历史记录
5.使用统一的依赖包管理库
6.每天集成一次

过去生产中存在的痛点

过去不智能不一体化的部署盘点:

  • 1.纯手工SCP
  • 2.纯手工登入git pull ,svn updata
  • 3.纯手工xftp往上拉
  • 4.开发给打包一个压缩包,rz上去,解压完成工程

缺点:

  • 1.全程运维参与,占用大量时间
  • 2.上线速度慢,一台一台上线
  • 3.人为操作失误多
  • 4.文件系统管理混乱
  • 5.回滚慢,不及时,容易造成大量的损失

正常的应用上线环境的规划:

(1)开发环境-开发者本地有自己的环境,然后运维需要设置的开发环境大家共用服务。例如:开发数据库mysql,其他redis、memcached.

(2)测试环境:功能测试环境和性能测试环境。

(3)预生产环境:生产环境集群中的某一个节点担任。

(4)生产环境:直接对用户提供服务环境。

预生产环境产生的原因:

  • 数据库不一致:测试环境和生产环境数据库肯定是不一样的。

  • 使用生产环境的联调接口。例如,支付接口。

如何设计一套生产自动化部署系统

  • 1.规划方案

  • 2.实现部署

  • 3.总结和扩展

  • 4.实际生产环境中的运用

生产中的部署例子

  • 1个集群中有10个节点

  • 实现一键部署这个10个节点

  • 一键回滚到任意版本

  • 一键回滚到上个版本

1.部署:


  • 代码放在哪?:svn、git

  • 获取什么版本的代码?

    • svn+git直接拉取某个分支

    • svn:指定版本号

    • git:指定tag

2.差异解决:


  • 各个节点直接差异:配置文件未必一样:crontab.xml 预生产节点

  • 代码仓库和实际的差异,配置文件是否放在仓库中。

  • config.snmple 配置文件只在部署身上有,单独的项目。

3.如何更新:


  • MV走再移动来一个新的。(野蛮)

  • java tomcat等需要重启

4.测试

5.串行和并行


  • 考虑是不是分组部署

6.如何执行:


  • 1.shell ./执行

  • 2.web界面 –例子:腾讯蓝鲸

生产中存在的安全问题:

  • 开发不应该知道当前的版本号,运维应该来控制知道版本号

  • 帐号的用户密码,应该运维来管理

  • master帐号密码应该主管来管理

  • 如果涉及到支付的KEY问题,知道的人越少越好,权限的保密。

  • Web用户应该为普通用户,所有的WEB服务都不应该监听80,除了负载均衡

流程图

集成上线流程图

实际部署:

创建普通用户双机互信:

groupadd www
useradd -g www www  
ssh-keygen -t rsa -P ''   ##一路回车
ssh-copy-id -i ~/.ssh/id_rsa.pub root@IP
ssh IP 'ifconfig'         ##测试是否连通

回滚流程图
一键回滚

整体代码:

#!/bin/bash
# author=ddy4633

# Node List
PRE_LIST="192.168.175.192"
GROUP_LIST="192.168.175.193"
ROLLBACK_LIST="192.168.175.192 192.168.175.193"

# Date Env
TIME=(date "+%Y-%m-%d-%H-%M-%S")   # tar 中出现 ":"会报错 DATE=(date "+%Y-%m-%d-%T")

# SHell Env
SHELL_DIR='/home/www/'
SHELL_NAME='deploy.sh'
SHELL_LOG="{SHELL_DIR}/{SHELL_NAME}.log"

# Code Env
PRO_NAME="web-demo"
CODE_DIR="/deploy/code/web-demo"
CONFIG_DIR="/deploy/config/web-demo"
TMP_DIR='/deploy/tmp'
TAR_dir='/deploy/tar'
LOCK_FILE='/tmp/deploy.lock'


usage(){
    echo "Usage: 0 { deploy | rollback [ list | version] }"

}

write_log(){
    LOGINFO=1     echo "{DATE} : {SHELL_NAME} : {LOGINFO}" >> {SHELL_LOG} }  url_test(){     URL=1
    curl -s --head "URL" | grep "200"     if [ ? -ne 0 ];then
        shell_unlock;
        write_log "err : URL Rturn=false && exit"     fi     write_log "Text: URL --Return=Success"
    echo "URL curl is ok" }  shell_lock(){     touch {LOCK_FILE}

}

shell_unlock(){
    rm -rf {LOCK_FILE} }  code_get(){     write_log "code_get";     cd CODE_DIR && echo "git pull"
    cp -r {CODE_DIR} {TMP_DIR}/
    API_VER="V1.1"
}


code_java_build(){
    echo 'code_java_build'
}


code_config(){
    write_log "code_config"
    /bin/cp -r {CONFIG_DIR}/base/* {TMP_DIR}/"{PRO_NAME}"      PKG_NAME="{PRO_NAME}"_"API_VER"_"{TIME}"
    cd {TMP_DIR} && mv {PRO_NAME} {PKG_NAME} }  code_tar(){     write_log "code_tar"     cd {TMP_DIR} && tar -czf {PKG_NAME}.tar.gz {PKG_NAME} && write_log "tar czf {PKG_NAME}.tar.gz"  }  code_scp(){     for node in PRE_LIST;do
        scp {TMP_DIR}/{PKG_NAME}.tar.gz node:/opt/webroot/  # 保证能有www使用权限         write_log "code_scp node complate!"
    done
    for node in GROUP_LIST;do         scp {TMP_DIR}/{PKG_NAME}.tar.gz node:/opt/webroot/  # 保证能有www使用权限
        write_log "code_scp node complate!"     done }  pre_deploy(){     write_log "cluster_node_remove"     for node in PRE_LIST;do
        ssh node "cd /opt/webroot && tar zxf {PKG_NAME}.tar.gz"
        # 自动化部署的精髓软连接
        ssh node "rm -rf /webroot/web-demo && ln -s /opt/webroot/{PKG_NAME} /webroot/web-demo" 
        write_log "node-pre complate!" 
    done
    scp {CONFIG_DIR}/other/192.168.175.192.crontab.xml PRE_LIST:/opt/webroot/{PKG_NAME}/contab.xml     if [ ? -ne 0 ];then
        shell_unlock;
        write_log "Err: scp err !!!"
    fi
    url_test "http://{PRE_LIST}/index.html"     write_log "OK: pre_deploy addd to cluster seccess!" }  group_deploy(){     write_log "cluster_node_remove"     for node in GROUP_LIST;do
        ssh node "cd /opt/webroot && tar zxf {PKG_NAME}.tar.gz"
        # 自动化部署的精髓软连接
        ssh node "rm -rf /webroot/web-demo && ln -s /opt/webroot/{PKG_NAME} /webroot/web-demo" 
        write_log "node complate!" 
    done
    url_test "http://{GROUP_LIST}/index.html"     write_log "OK: pre_deploy addd to cluster seccess!"  }  config_scp(){      echo 'config_scp' }   cluster_node_in(){      echo 'cluster_node_in' }  rollback_fun(){     for node in ROLLBACK_LIST;do
#     if [ -d /opt/webroot/1];then         ssh node "rm -f /webroot/web-demo && ln -s /opt/webroot/1 /webroot/web-demo" #     fi     done  } rollback(){   if [ -z 1 ];then
    shell_unlock;
    echo "Err:Please input robblback version!" && exit;
  fi
    case 1 in         list)             ls -l /deploy/tmp/*.tar.gz             ;;         *)             rollback_fun 1
    esac
}

main(){
    if [ -f LOCK_FILE ];then     echo "Deploy is running" && exit;     fi     DEPLOY_METHOD=1
    ROLLBACK_VER=2     case DEPLOY_METHOD in
        deploy)
            shell_lock;
            code_get;
            code_java_build;
            code_config;
            code_tar;
            code_scp;
            pre_deploy;
            group_deploy;
            config_scp;
            url_test;
            cluster_node_in;
            shell_unlock;
            ;;
        rollback)
            shell_lock;
            rollback ROLLBACK_VER;             shell_unlock;             ;;         *)             usage;     esac } main 1 $2

Git的介绍

GIT的生态

  • Git 分布式版本管理系统

  • Gitlab git 私库解决方案

  • Gitlab git 公有库解决方案

  • 1.GIT基础

  • 2.分支管理

  • 3.GIT高级

  • 4.远程管理

Git的原理

  • 4个区域

  • 4个状态

版本控制器的发展

常用命令

基本命令名称 相关作用
git add 加入暂存(索引区)
git status 查看状态
git status -s 状态概览
git diff 尚未暂存的文件
git diff –staged 暂存区文件
git commit 提交更新
git reset 回滚
git rm 从版本库中移除
git rm –cached Readme 从暂存区中移除
git mv 相当于MV git rm git add 三个 命令

简单的Git编译安装

官方那个地址:https://github.com/git/git/

环境安装

yum install curl-devel expat-devel gettext-devel openssl-devel zlib-devel gcc perl-ExtUtils-MakeMaker

下载编译

wget https://github.com/git/git/archive/v2.7.4.zip
unzip v2.7.4.zip
cd git-2.7.4
make prefix=/usr/local/git all
make prefix=/usr/local/git install
rm -rf /usr/bin/git
ln -s /usr/local/git/bin/git /usr/bin/git
git --version

Git初始化

git init
git config --global user.name "git账号"
git config --global user.email 邮箱地址
git config --list

Git基础操作

Git高级知识

  • git chechout 用于切换分支

Checkout一个文件和带文件路径Git reset非常像,除了它更改的是工作目录而不是缓存区。不像提交层面的checkout命令,它不会移动HEAD引用,也就是你不会切换到别的分支上去。
如果你缓存并且提交了checkout的文件,它具备将某个文件回撤到之前的版本的效果。注意它撤销了这个文件后面所有的更改,而Git revert命令只是撤销某一个特定提交的更改。


– git check –file.txt 撤销对文件的修改

  • git reset 回滚
    • –soft 缓存区和工作目录都不会被改变

    • –mixed 默认选项,缓存区和你指定的提交同步但是工作目录不受到影响

    • –hard 缓存区和工作目录都同步到你指定的提交

文件层操作

  • 当检测到文件路径时,Git reset将存储区同步到你指定的目录中去。

  • git reset HEAD~2 文件名

  • 运行git reset

Git远程管理

原理图

github上clone自己的项目

git clone 自己项目地址

gitlab私有库部署和回滚

  • 什么是Gitlab

GitLab是一个利用 Ruby on Rails 开发的开源应用程序,实现一个自托管的Git项目仓库,可通过Web界面进行访问公开的或者私人项目。
GitLab拥有与Github类似的功能,能够浏览源代码,管理缺陷和注释。可以管理团队对仓库的访问,它非常易于浏览提交过的版本并提供一个文件历史库。它还提供一个代码片段收集功能可以轻松实现代码复用,便于日后有需要的时候进行查找。

  • 一个基于Git的源码托管解决方案

  • 基于Ruby on rails 开发

  • 集成了Nginx postgreSQL redis sidekiq等组件

Gitlab的组件

  • Nginx:静态Web服务器

  • gitlab-shell:用于处理Git命令和修改authorized keys列表

  • gitlab-workhorse:轻量级的反向代理服务器

  • logrotate:日志文件管理工具

  • postgresql:数据库

  • redis:缓存数据库

  • sidekiq:用于在后台执行队列任务(异步执行)

  • unicorn:GitLab Rails应用是托管在这个服务器上面的

Gitlab相关目录

  • /var/opt/gitlab/git-data/repositories/ -> 默认存储目录

  • /var/opt/gitlab -> gitlab-ctl reconfigure命令编译后的应用数据和配置文件,不需要人为的去修改配置

  • /etc/gitlab -> 配置文件目录

  • /var/log/gitlab -> 此目录下存放了Gitlab各个组件产生的日志

  • /var/opt/gitlab/backups/ -> 备份文件生成的目录

变更主配置文件

  • gitlab-ctl reconfgure 重置配置文件

  • gitlab-ctl show-config 验证配置文件

  • gitlab-ctl restart 重启服务

1.配置的基础环境部署

yum install curl policycoreutils openssh-server openssh-clients postfix
systemctl start postfix

2.配置国内的YUM源

vim /etc/yum.repos.d/gitlab-ce.repo
    [gitlab-ce]
    name=gitlab-ce
    baseurl=https://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/yum/el7/
    repo_gpgcheck=0
    gpgcheck=0
    enabled=1
    gpgkey=https://packages.gitlab.com/gpg.key
yum makecahe
yum -y install gitlab-ce

3.配置启动Gitlab-ce

vim /etc/gitlab/gitlab.rb
    external_url 'http://IP:port'
gitlab-ctl reconfigure
如果使用的是虚拟机把内存分配为2G左右最好,否则占用wap分区。

4.访问gitlab

curl http://IP:port
第一次安装需要修改默认的root密码

5.本地不需要注册所以关闭注册功能

6.上传密钥实现SSH克隆:

ssh-keygen -t dsa -f /root/.ssh/id_dsa  -P "" #非交互式生成密钥
需要的机器上 ssh-keygen 生成密钥
cat .ssh/id_rsa.pub  公钥
复制到Web上保存下来
当你使用SSH克隆时候如果提示需要输入密码则表示你需要配置密钥了,否则永远无法克隆下来!

配置密钥

7.创建用户组

创建用户组

8.创建用户

用户名 职责
cto 不解释BOSS,管理者
dev01 开发玩家一,linux
dev02 开发玩家二,windos

9.创建项目

克隆或者上传文件

cd /deploy/code && rm -rf web-demo
git clone git@192.168.191.161:root/my_python.git  #克隆

使用windos连接Gitlab

  • 下载安装包

  • 除了以下的选项其他的统一默认下一步

  • 在你磁盘上创建一个新的文件夹

  • 进入你创建的目录,单击右键git bash here

  • 创建密钥,存放在:C:\Users\Administrator.ssh

  • 使用新建的开发者用户登入gitlab,授权project并重复之前的条件KEY

Gitlab备份与恢复

  • 配置文件中加入
gitlab_rails['backup_path'] = "/var/opt/gitlab/backups" #备份的路径
gitlab_rails['backup_archive_permissions'] = 0644   #权限
  • 如果自定义备份目录需要富裕git权限
    • mkdir /data/backup/gitlab

    • chown -R git.git /data/backup/gitlab

  • 定时任务Crontab中计入

0 2 * * * /usr/bin/gitlab-rake gitlab:backup:create
  • 策略建议:本地保留3天、在异地备份永久保留

重载配置

gitlab-ctl reconfigure
gitlab-ctl restart
gitlab-rake gitlab:backup:restore BACKUP=备份的时间戳     #执行数据的恢复
    gitlab-ctl restart  #等待30秒后恢复数据

数据的恢复

  • 停止数据的写入服务

  • gitlab-ctl stop unicorn

  • gitlab-ctl stop sidekiq

配置Gitlab邮件通知

  • 需要在配置文件中开启所有的选项

  • 合并代码工作任务自动邮箱通知

gitlab_rails['time_zone'] = 'Asia/Shanghai'
gitlab_rails['gitlab_email_enabled'] = true
gitlab_rails['gitlab_email_from'] = '发件人@xxx.com'
gitlab_rails['gitlab_email_display_name'] = 'gitlab'
gitlab_rails['smtp_enable'] = true
gitlab_rails['smtp_address'] = "smtp.126.com"
gitlab_rails['smtp_port'] = 25
gitlab_rails['smtp_user_name'] = "ddy"
gitlab_rails['smtp_password'] = "your_password"
gitlab_rails['smtp_domain'] = "126.com"
gitlab_rails['smtp_authentication'] = "login"

项目部署

某项目的规划

需求 开发人员 完成时间
首页 dev01 xx.xx
新闻 dev01 xx.xx
支付 dev02 xx.xx
关于 dev02 xx.xx

cto定制开发计划

  • cto项目经理定制项目任务

  • 构建项目计划表

  • 发布新的任务

  • 分配所有的任务

什么是jenkins

  • 什么是JenKINS?

持续集成、自动测试、持续部署的超级引擎,支持自定义工具集、多种交付通道。

  • jenkins存在的坑

jenkins卡启动,机器连接网络出现问题,不断的连接官方网站,关闭网络,离线安装模式。

jenkins的安装及其部署

1.环境的初始化

  • 1.1 iptables、firewalld、selinux、NetworkManage 四件套干掉

  • 1.2 Jenkins运行在JAVA环境下所以jdk

  • 1.3 yum install java-1.8.0-openjdk java-1.8.0-openjdk-devel

  • 1.4 上清华的开源镜像网

    • https://mirrors.tuna.tsinghua.edu.cn/jenkins/redhat/ # jenkins源可以YUM安装也可以RPM
  • 1.5 清华的centos-7-epel安装方法
    • https://mirrors.tuna.tsinghua.edu.cn/help/centos/
  • 1.6 yum安装Jenkins启动,8080开放就说明开启成功

  • 1.7 登入ip:8080

  • 1.8 cat /var/lib/jenkins/secrets/initialAdminPassword # 查看jenkins的初始密码

Jenkins的目录

  • /var/lib/jenkins 主目录
  • /etc/init.d/jenkins 启动文件
  • /var/cache/jenkins 程序文件
  • /var/log/jenkins 日志文件

jenkins的升级

systemctl stop jenkins
cd /usr/lib/jenkins
mv 老版本 老版本.back   # 备份一下

如图所示:

2.网页的安装

Jenkins插件plugins

  • 手动下载插件:https://plugins.jenkins.io/

    rz plugins.tar.gz
    tar xf mv plugins.tar.gz && plugins /var/lib/jenkins/plugins && chown -R jenkins:jenkins /var/lib/jenkins/plugins

freetype job

#!/bin/sh
export PATH="/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin"

#Print env variable
echo "[INOF] --> Print env variable"
echo "Current deployment envrionment is Deployment_env" >> test.properties echo "The build is Version" >> test.properties
echo "[INOF] --> Done ...."

#Check test properties
echo "[INOF]Check test properties"
if [ -s test.properties ]
then
    cat test.properties
    echo "[INFO] --> Done ...."
else
    echo "test.properties is empty!"
fi
echo "[INOF] Build finished !!!"

pipeline基础架构

  • 所有的代码包裹在pipeline{}层内

  • stages{}层用来包含该pipeline所有stage子层

  • stage{}层用来包含具体的我们需要的编写任务的steps{}层

  • steps{}层用来添加具体需要调用的模块语句

pipeline Job编写规范

  • agnet区域
agent定义:pipeline在哪里运行可以使用any,none或具体的jenkins node主机名等

例如:agent{node{label 'node1'}}
  • environment区域
(1)变量名称=变量值 #定义环境变量
(2)可以定义全局环境变量,应用所有stages任务
(3)可以定义stage环境变量,应用单独的stage任务
  • script区域

  • groovy脚本语言

  • 可以编写脚本逻辑运算

  • steps区域

(1)echo:打印输出
(2)sh:调用Linux系统的shell命令
(3)git url:调用git模块进行git相关的操作

构建配置过程

#!groovy

pipeline {
    agent {node {label 'master'}}

    environment {
        PATH="/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin"
    }

    parameters {
        choice(
            choices: 'dev\nprod',
            description: 'choose deployment environment',
            name: 'Deployment_env'
            )
        string(name: 'Version', defaultValue: '1.0.0', description: 'Build Version !!!')
    }
    stages {
        stage("Checkout Test Repo") {
            steps{
                sh 'git config --global http.sslVerify false'
                dir ("{env.WORKSPACE}") {                     git branch: 'master', credentialsId:"2e3b5f3a-12e1-45ad-9257-6b216048b1e0",url: 'http://192.168.42.145:3000/root/ddy.git'                 }             }         }         stage("Print env variable") {             steps {                 dir ("{env.WORKSPACE}") {
                    sh """
                    echo "[Begin] -------------------------"
                    echo "[Title] ---> Print env variable "
                    echo "[Event] --> Current deployment environment is Deployment_env" >> test.properties                     echo "[Event] --> The Build is Version" >> test.properties
                    echo "[INFO] ---> Done ......."
                    echo "[END]  --------------------------"
                    """
                }
            }
        }
        stage("Check Test Properties") {
            steps {
                dir ("${env.WORKSPACE}") {
                    sh """
                    echo "[Begin] -------------------------"
                    echo "[Title] ---> Check Test Properties"
                    if [ -s test.properties ]
                    then 
                        cat  test.properties
                        echo "[INFO] --> Done ......"
                    else
                        echo "test.properties is empy"
                    fi
                    echo "[INFO] Build finished ..."
                    """
                }
            }
        }
    }
}

jenkins应用

#!/bin/sh 

echo "--------------欢迎使用自动化构建系统----------------"
echo "The Current user is 【 `whoami` 】"
echo "The Current Build Environment is 【 deployment_env 】" echo "The Current Version is 【 version 】"
echo "The Current Password is 【 password 】"  if bool
then
    echo "Request is approved -> ok"
else 
    echo "Request is rejected -> err"
fi

echo "--------------end-----------------"

jenkins集成演示环节

发表评论

电子邮件地址不会被公开。 必填项已用*标注