ezdpl Linux自动化部署实战
最近把ezdpl在生产环境中实施了,再加上这段时间的一些修改,一并介绍一下。
再次申明:
- ezdpl不是开箱即用的,需要根据自己的应用环境定制。对初学者来说使用起来反倒困难更多、风险更大。
- 它不是一个通用的项目,更多的是提供一种思路,将繁琐的操作变得简单易行,而且是用最原始的上传文件、执行脚本的方式。但是要享受简单,首先要做艰苦的准备和测试工作。
地址: https://github.com/Panblack/ezdpl
一、说明
1、组成
1) ezdpl.sh 主脚本,批量部署用的 auto.sh 脚本
2) 应用目录,可以包含任意个版本目录
3) 版本目录,含files和可选的 pre.sh、fin.sh 脚本
2、工作目录
├── 应用A
│ ├── 版本1
│ │ ├── files
│ │ │ ├── etc
│ │ │ ├── usr
│ │ │ └── opt
│ │ ├── pre.sh
│ │ └── fin.sh
│ ├── 版本2
│ │ └── fin.sh
│ ├── 版本3
│ │ └── files
├── 应用B
│ └── 版本1
│ └── files
├──ezdpl.sh
└──auto.sh
3、流程
首先操作机需要能无密码登录所有目标服务器,指令 ' ssh-keygen -t rsa ; ssh-copy-id 用户名@目标服务器 ' 。
主脚本有2/3是判断参数和目标服务器是否合法,真正的操作部分只有三处:
1) 如果有 pre.sh 脚本,就上传并在目标服务器执行;
2) 复制 files 目录下的所有文件到目标服务器的根目录 /;
3) 如果有 fin.sh 脚本,就上传并在目标服务器执行;
最后判断是否要重启目标服务器。
为什么要有两个脚本呢?很简单,复制文件之前可能需要对系统进行配置,有些系统配置需要特定文件上传之后。
具体怎么用?看您心情。
4、用法
./ezdpl.sh <Silent Mode Y|N> <ip address>:[port] <app/version> [reboot Y|N(N)] [username(root)]
主脚本共 5 个参数
<Silent Mode Y|N> Y - 静默模式, N - 需要手工确认,只能是 Y 或 N 。
<ip address>:[port] 目标服务器 IP地址:端口,如果目标服务器sshd端口不是默认的 22,就需要指明。
<app/version> 工作目录下的应用目录和版本,比如 orders/20151012 。
[reboot Y|N(N)] 执行完 fin.sh 脚本后是否重启,一般新装系统往往需要重启。默认为 N,可省略。
[username(root)] 执行远程登录的用户名,默认是 root,可省略。
5、最佳实践
* 能用文件解决的就尽量不用脚本,除非你的sed、awk、正则表达式功底深厚并且愿意承担风险。文件的好处是准确率高,便于事先审核、事后排错。
* 在测试环境配置一套“干净”的系统,然后将配好的文件复制到 ezdpl 工作目录。记住文件需要带完整路径,用' cp --parents '就可以了。
* 如果有软连接则必须压缩打包再传输,因为 scp 会将软连接复制成目标文件。
* 稳定版本保持不动,用' chattr +i ' 指令保护起来,或者打包备份,防止意外修改。微小变更也要建立新的版本并加以说明,以便跟踪变更历史,而且利于回退。
* 累积的小变更定期合并到新的稳定版。
cp --parents 示例,我们要从服务器 webserver1 上复制出 httpd 的配置文件:
[root@webserver1:/etc/httpd]# cp -r --parents ./conf /tmp/files
结果会得到:
/tmp/files/etc/httpd/conf/ (含conf内的文件和目录)
顺便说一下,要让 CentOS 在提示符显示全路径,在 /root/.bash_profile 末尾添上这一行:
PS1='[\u@\h:$PWD]# '
注意大小写、单引号并且井号后面有个空格。
再执行
source /root/.bash_profile
如果要让新建用户也具备这个特性,在 /etc/skel/.bash_profile 末尾添上这一行:
PS1='[\u@\h:$PWD]$ '
注意要用美元符 。
二、范例
1、场景
为新装操作系统准备的应用服务器初始化环境,“应用/版本” 为 appserver/current 。
[root@operation:/opt/ezDpl]# ll
total 28
-rw-r--r-- 1 root root 304 Oct 24 18:49 auto.sh
-rw-r--r-- 1 root root 3383 Oct 24 18:57 ezdpl.sh
drwxr-xr-x 3 root root 4096 Oct 24 13:48 appserver
drwxr-xr-x 3 root root 4096 Oct 24 13:49 loadbalance
drwxr-xr-x 3 root root 4096 Oct 24 13:49 orders
drwxr-xr-x 3 root root 4096 Oct 24 13:49 stocks
drwxr-xr-x 3 root root 4096 Oct 24 13:49 crm
2、appserver目录结构
appserver/
├── current
│ ├── files
│ │ │ ├── cron.daily
│ │ │ │ └── ntpsync
│ │ │ ├── profile
│ │ │ ├── profile.d
│ │ │ │ └── colorls.sh
│ │ │ ├── security
│ │ │ │ └── limits.conf
│ │ │ ├── skel
│ │ │ │ └── .bash_profile
│ │ │ ├── sysconfig
│ │ │ │ └── iptables
│ │ │ └── sysctl.conf
│ │ ├── opt
│ │ │ ├── jdk1.8.0_65
│ │ │ │ └── bin
│ │ │ ├── logs
│ │ │ ├── packages
│ │ │ └── tomcat8
│ │ │ ├── bin
│ │ │ ├── conf
│ │ │ ├── lib
│ │ │ ├── temp
│ │ │ ├── webapps
│ │ │ └── work
│ │ └── usr
│ │ └── local
│ │ └── bin
│ ├── fin.sh
│ └── pre.sh
└──20151012
└── fin.sh
上述目录结构中,etc目录下是已经改写好的配置文件,分别为
etc/cron.daily/ntpsync | ntpdate 0.pool.ntp.org 1.pool.ntp.org 自动获取网络时间 |
etc/profile | 设置java环境变量 |
etc/profile.d/colorls.sh | 用 2015-10-12 09:00 的格式显示文件日期时间,alias ll='ls -l --color=auto --time-style=long-iso' 2>/dev/null |
etc/security/limits.conf | 修改ulimits值以适应高并发 |
etc/skel/.bash_profile | 设定新建用户的环境 |
etc/sysconfig/iptables | 防火墙设置 |
etc/sysctl.conf | 内核参数 |
opt里面是基础应用,比如 jdk,调整好的 tomcat 等,上传到目标服务器的 /opt 目录。
usr/local/bin 里面是平常使用的服务器管理脚本,上传到目标服务器的 /usr/local/bin 目录。
3、pre.sh 脚本
作用:为无法连接外网的服务器配置内部 yum 源(源必须事先准备好,本例中源所在服务器为10.6.1.200),安装必要的包,备份原始配置文件。
#!/bin/bash
mkdir -p /etc/yum.repos.d/temp
mv /etc/yum.repos.d/* /etc/yum.repos.d/temp local_repo="
[Local]
name=Local repo
baseurl=http://10.6.1.200/centos6
gpgcheck=0
enabled=1
"
echo -e "$local_repo" > /etc/yum.repos.d/local.repo nginx_repo="
[nginx]
name=nginx repo
baseurl=http://10.6.1.200/nginx
gpgcheck=0
enabled=1
"
echo -e "$nginx_repo" > /etc/yum.repos.d/nginx.repo yum -y install telnet man vim wget zip unzip ntpdate tree gcc iptraf tcpdump bind-utils
yum -y install nginx
echo
echo "Packages installed..."
echo
/bin/cp /etc/sysconfig/iptables /etc/sysconfig/iptables.`date +%Y%m%d`
/bin/cp /etc/security/limits.conf /etc/security/limits.conf.`date +%Y%m%d`
/bin/cp /etc/sysctl.conf /etc/sysctl.conf.`date +%Y%m%d`
#....(其余文件备份指令省略)
4、fin.sh 创建用户,并成为应用程序目录所有者
#!/bin/bash
useradd operuser && echo HisPassWord | passwd --stdin operuser
chown -R operuser:operuser /opt
5、auto.sh
将appserver的current版本依次部署到10.6.1.x等五台服务器上。简单吧?
#!/bin/bash
sh ezdpl.sh Y 10.6.1.11 appserver/current Y
sh ezdpl.sh Y 10.6.1.12 appserver/current Y
sh ezdpl.sh Y 10.6.1.13 appserver/current Y
sh ezdpl.sh Y 10.6.1.14 appserver/current Y
sh ezdpl.sh Y 10.6.1.15 appserver/current Y
为了达到并行的目的,auto.sh脚本可以稍加修改,比如:
sh ezdpl.sh Y 10.6.1.11 appserver/current Y > /tmp/10.6.1.11.log &
sh ezdpl.sh Y 10.6.1.12 appserver/current Y > /tmp/10.6.1.12.log &
sh ezdpl.sh Y 10.6.1.13 appserver/current Y > /tmp/10.6.1.13.log &
...
6、变更
服务器运行一段时间后需要统一修改 operuser 的密码,并且将该用户加入到 developing 组。
将指令写入 fin.sh 脚本(pre.sh 也行,因为此项变更不涉及到上传文件,所以没有前后之分)。
#!/bin/bash
echo HisNewPassWord | passwd --stdin operuser
usermod -aG developing operuser
修改auto.sh脚本并执行。
#!/bin/bash
sh ezdpl.sh Y 10.6.1.11 appserver/ Y > /tmp/10.6.1.11.log &
sh ezdpl.sh Y 10.6.1.12 appserver/ Y > /tmp/10.6.1.12.log &
sh ezdpl.sh Y 10.6.1.13 appserver/ Y > /tmp/10.6.1.13.log &
sh ezdpl.sh Y 10.6.1.14 appserver/ Y > /tmp/10.6.1.14.log &
sh ezdpl.sh Y 10.6.1.15 appserver/ Y > /tmp/10.6.1.15.log &
也很简单对吧?
7、回退
部署了应用orders的版本20151018,但是应用出现新的BUG,要回退到版本20151012。
部署:(部署时的 pre.sh 一般要包含删除服务器当前版本的指令)
sh ezdpl.sh Y 10.6.1.11 orders/20151018 Y > /tmp/10.6.1.11.log &
sh ezdpl.sh Y 10.6.1.12 orders/20151018 Y > /tmp/10.6.1.12.log &
sh ezdpl.sh Y 10.6.1.13 orders/20151018 Y > /tmp/10.6.1.13.log &
...
回退:(相当于部署上一个版本,当然,pre.sh 脚本会先删除有BUG的 版本20151018。还是很简单吧?)
sh ezdpl.sh Y 10.6.1.11 orders/20151012 Y > /tmp/10.6.1.11.log &
sh ezdpl.sh Y 10.6.1.12 orders/20151012 Y > /tmp/10.6.1.12.log &
sh ezdpl.sh Y 10.6.1.13 orders/20151012 Y > /tmp/10.6.1.13.log &
...
但是,依旧强烈建议在生产环境实施之前,要做充分的测试。
三、ezdpl.sh 版本1.1
#!/bin/bash
# https://github.com/Panblack/ezdpl # Check Parameters
#echo $
#echo $
#echo $
#echo
if [ -n "$1" ]; then
_silent=$
if [ "$_silent" != "Y" ]; then
if [ "$_silent" != "N" ]; then
echo "The first parameter must be Y or N. Exit!"
exit
fi
fi
else
echo "silent. Usage: ./ezdpl.sh <Silent Mode Y|N> <ip address>:[port] <app/version> [reboot Y|N(N)] [username(root)]"
exit
fi if [ -n "$2" ]; then
#Detailed param check will be needed.
_ipaddress=$(echo $|awk -F':' '{print $1}')
_port=$(echo $|awk -F':' '{print $2}')
if [ ${#_port} -eq ]; then
_port=""
fi
else
echo "ipaddress:port. Usage: ./ezdpl.sh <Silent Mode Y|N> <ip address>:[port] <app/version> [reboot Y|N(N)] [username(root)]"
exit
fi if [ -n "$3" ]; then
_app_version=$
else
echo "app/version. Usage: ./ezdpl.sh <Silent Mode Y|N> <ip address>:[port] <app/version> [reboot Y|N(N)] [username(root)]"
exit
fi # Optional parameters
if [ -n "$4" ]; then
_reboot=$
else
_reboot="N"
fi
if [ -n "$5" ]; then
_username=$
else
_username="root"
fi # Silent mode or not
if [ "$_silent" != "Y" ]; then
echo
echo "Ezdpl does things in a raw and simple way."
echo "https://github.com/Panblack/ezdpl"
echo
echo "Will initialize a new server, or deploy apps to a certain server, or upgrade a production server."
echo "Usage: ./ezdpl.sh <Silent Mode Y|N> <ip address>:[port] <app/version> [reboot Y|N(N)] [username(root)]"
echo "Manually Initialize 10.1.1.1: ./ezdpl.sh N 10.1.1.1 common/current Y"
echo "Silently Deploy app_a to 10.1.1.1: ./ezdpl.sh Y 10.1.1.1:22 app_a/current Y root"
echo "Silently Upgrade 10.1.1.2's app_a: ./ezdpl.sh Y 10.1.1.2:2222 app_a/20150720"
echo "Manually Upgrade 10.1.1.2's conf: ./ezdpl.sh N 10.1.1.2:2222 app_a/2015-10-12"
echo # Confirmation
read -p "Will overwrite configuration files or apps on $_ipaddress. Enter Y to continue: "
if [ "$REPLY" != "Y" ]; then
echo "Exit"
exit
fi # Confirmation again
read -p "Are you sure? Enter Y to continue: "
if [ "$REPLY" != "Y" ]; then
echo "Exit"
exit
fi
fi # Check
echo "Target Server: ${_ipaddress}..."
ssh -p $_port $_username@$_ipaddress uname > /dev/null
if [ "$?" != "" ]; then
echo
echo "$_ipaddress is not reachable. "
exit
fi if [ ! -d "./$_app_version" ]; then
echo
echo "There is no $_app_version configured here !"
exit
fi # Everything seems OK. Go!
# Run pre.sh on the target server
if [ -f "./$_app_version/pre.sh" ]; then
scp -P $_port ./$_app_version/pre.sh $_username@$_ipaddress:/tmp/
ssh -p $_port $_username@$_ipaddress sh /tmp/pre.sh
echo "$_username@$_ipaddress:/tmp/pre.sh executed."
fi # Start copy app/version/files/*
if [ -d ./$_app_version/files ]; then
scp -P $_port -r ./$_app_version/files/* $_username@$_ipaddress:/
echo "./$_app_version/files/* copied."
fi # Run fin.sh on the target server
if [ -f "./$_app_version/fin.sh" ]; then
scp -P $_port ./$_app_version/fin.sh $_username@$_ipaddress:/tmp/
ssh -p $_port $_username@$_ipaddress sh /tmp/fin.sh
echo "$_username@$_ipaddress:/tmp/fin.sh executed."
fi # Reboot target server.
if [ "$_reboot" = "Y" ]; then
echo
echo "Target server will reboot..."
echo
ssh -p $_port $_username@$_ipaddress reboot
fi
echo "Target Server: ${_ipaddress} done!"; echo
# End of ezdpl.sh
ezdpl Linux自动化部署实战的更多相关文章
- Linux 自动化部署DNS服务器
Linux 自动化部署DNS服务器 1.首先配置主DNS服务器的IP地址,DNS地址一个写主dns的IP地址,一个写从dns的地址,这里也可以不写,在测试的时候在/etc/resolv.conf中添加 ...
- Linux 自动化部署Rsyslog服务
Linux 自动化部署Rsyslog服务 源码如下: #/bin/bash #该脚本用于自动化部署Ryslog服务配置 #作者:雨中落叶 #博客:https://www.cnblogs.com/yuz ...
- Linux自动化部署尝试
Linux自动化部署尝试 最近做一个项目临近测试,购买的是阿里云的服务器,每次部署都是手动打包war,然后上传到服务器,然后修改配置文件,不仅繁琐,而且费时,就思索着找一个一键式的部署方式,今天终 ...
- Linux 自动化部署
1.pexpect Pexpect 是 Don Libes 的 Expect 语言的一个 Python 实现,是一个用来启动子程序,并使用正则表达式对程序输出做出特定响应,以此实现与其自动交互的 Py ...
- Jenkins持续集成git、gitlab、sonarqube(7.0)、nexus,自动化部署实战,附安装包,严禁转载!!!
导读 之前用的都是SVN,由于工作需要用到Git,求人不如求己,技多不压身,多学一项技能,未来就少求别人一次,系统的学一遍,自己搭建一整套环境,自动化部署(自动发版),代码质量检测等等(为啥不用doc ...
- 基于Jenkins+Gitlab的自动化部署实战
故事背景 一个中小型企业,是典型的互联网公司,当初期的时候可能运维只能标配到2~3人,此时随着公司的发展,项目会逐渐增多.前期部署项目可能都是手动的, 俗称“人肉部署”,这简直是无比的痛苦,不能忍受的 ...
- 一次Linux自动化部署尝试
最近做一个项目临近测试,购买的是阿里云的服务器,每次部署都是手动打包war,然后上传到服务器,然后修改配置文件,不仅繁琐,而且费时,就思索着找一个一键式的部署方式,今天终于腾出时间来做这件事,记录一下 ...
- jenkins 自动化部署实战
jenkins 作为一个自动化的集成工具,已经是必不可少的了.它里面提供各种插件,以及完备的基础流程设施,为大家的自动化集成之路提供了很多的方便.所以,我们有必要完整的实践一回.以切身体会到它的好处! ...
- Kickstart + http Linux自动化部署服务端
设备需要开启Network Boot功能.具体PXE技术就另外提,本文主要讲解配置. 在搭建该服务器之前需要关闭SELinux和iptables不然可能dhcp服务都起不来,客户端收不到IP地址,无法 ...
随机推荐
- 怎样关闭adobe reader的自动更新
https://jingyan.baidu.com/article/1612d5004390ebe20f1eee50.html
- Qt 学习之路 2(60):使用 DOM 处理 XML
Qt 学习之路 2(60):使用 DOM 处理 XML 豆子 2013年8月3日 Qt 学习之路 2 9条评论 DOM 是由 W3C 提出的一种处理 XML 文档的标准接口.Qt 实现了 DO ...
- C++_异常4-将对象用作异常类型
通常,引发异常的函数将传递一个对象.这样做的重要优点之一就是,可以利用不同的异常类型来区分不同的函数在不同的情况下引发的异常. 对象可以携带信息,程序员可以根据这些信息来确定异常的原因. 同时,cat ...
- 洛谷 P4036 [JSOI2008]火星人(splay+字符串hash)
题面 洛谷 题解 首先,我们知道求最长公共前缀可以用二分答案+hash来求 因为有修改操作, 考虑将整个字符串的hash值放入splay中 接着就是splay的基本操作了 Code #include& ...
- bzoj3224 普通平衡树 splay模板
题目传送门 题目大意:完成一颗splay树. 思路:模板题,学着还是很有意思的. 学习splay树:蒟蒻yyb 该题模板:汪立超 #include<bits/stdc++.h> #defi ...
- HDU - 1907 anti-SG
题意:nim游戏,最后取光为[输] anti-SG的应用,搬运一下我的摸鱼小笔记 最先看到的应该是分奇偶的非充裕堆判断,若为偶数则先手胜,否则后手胜 按SG分类 SG!=0时 1.只有一堆大于1,先手 ...
- 使用Junit进行自动单元测试
软件工程第二次作业 选择开发工具 使用Eclipse进行java程序编写:安装过程如图: 练习自动单元测试技术 参考资料:[Junit入门使用教程][https://www.cnblogs.com/y ...
- 剑指offer——面试题4:二维数组中的查找
// 面试题4:二维数组中的查找 // 题目:在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按 // 照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个 // 整数 ...
- PIE SDK PCA融合
1.算法功能简介 PCA 融合分三步实现,首先将多光谱数据进行主成分变换,然后用高分辨单波段替换第一主成分波段,最后进行主成份逆变换得到融合图像. PIE支持算法功能的执行,下面对PCA融合算法功能进 ...
- pl/sql过期问题解决
第一步: 输入cmd进入命令窗口 命令窗口中输入 regedit HKEY_CURRENT_USER\Software\Allround Automations 删除Allround Automati ...