大家好,欢迎来到IT知识分享网。
ezdpl是easy deployment的简写,使用简单的ssh和shell脚本来部署、升级、回滚和重新配置linux服务器。
重要提示:
警告:这个项目还处于测试过程中,请仔细阅读说明,并且自己承担可能带来的风险。
最佳实践:根据自己的生产环境修改脚本,部署之前需要充分测试。
最新版本请关注我的github https://github.com/Panblack/ezdpl
为什么要写ezdpl?
现在很流行使用puppet之类的工具进行自动化的系统配置。puppet方便、高效而且可以在实际配置之前“预演”,日常工作可以简化为编写puppet脚本,剩下的让puppet自己去忙活就行了,可以轻松管理成百台的服务器。
不过有人就是对这个东西不感冒,也许没有那么多服务器,也许学习另一套“系统”来管理手头的系统是个负担。我就是这种情况,而且,我喜欢用“原始、简单”的方法,不要什么代理、插件、模块、剧本什么的。我必须始终知道服务器具体是怎么配置的,配置文件是咋写的。如果习惯了puppet之类的工具,哪天碰上没有这些工具的环境怎么干活呢?这可不是件令人欣慰的事情。
但是,自动化管理确实很必要。不用puppet之类的工具怎么管理一大堆服务器呢?对了,用shell脚本。只需要一台操作机(或者叫跳板机),保存着初始化或者升级系统用的脚本、配置文件和应用,所有文件都是“原始”形态,甚至目录结构都跟生产服务器一样。操作机具有对目标服务器的root免密码登录权限以便自动运行,所有工作仅仅需要一个脚本。
“等一等,哥们,ansible就是这么做的。你这不是重复造轮子吗?不明智!”你笑了吧?
没错,我是在重复造轮子,不过是个更简单的轮子,只为了好玩。而且呢,我不需要担心忘掉指令啊脚本啊这些“终极武器”,这很让人欣慰啊,呵呵呵。
用原始、简单的方式工作
ezdpl非常非常简单,仅仅用到如下技术:
* 精心组织的目录和文件(最关键的其实在这儿)
* scp(比如 ‘scp -r 目录 root@目标服务器:/ ‘)
* ssh(比如 ‘ssh root@目标服务器 指令 ‘)
基本的目录结构,有三个级别
级别0:ezdpl文件
级别1:应用名
级别2:版本
对某个应用服务器的任何变更或更新,都在“版本”级别建立一个新的目录来实现。
如果需要回滚,只需要在脚本参数里指定上一版本即可。
开始的设想比现在复杂得多,目录层次也很乱。现在的方案实实在在的说明了简单就是美。
场景:
* 所有服务器(操作机,目标服务器)都安装了 Centos6 x86_64
* 目标服务器仅配置了IP地址和主机名
* 操作机具有对所有目标服务器的root免密码登录权限,如果没有,则脚本运行时需要输入密码
* ezdpl部署在操作机 /home/ezdpl目录
* 操作机的ssh密钥最好有passphrase密码保护
* 所有目标服务器的应用都部署在/opt
置备应用目录
应用需要的目录和文件可以从头手工建立,或者从当前的生产服务器复制。以下指令会很有帮助:
[root@java_c-server /] mkdir -p /tmp/java_c [root@java_c-server /] /bin/cp -r --parents /etc/logrotate.d/java_c /tmp/java_c [root@java_c-server /] /bin/cp -r --parents /home/operuser/bin /tmp/java_c [root@java_c-server /] /bin/cp -r --parents /opt/java_c /tmp/java_c [root@java_c-server /] find /opt/logs/ -type d -exec mkdir -p /tmp/java_c/{} \; [root@java_c-server /] scp -r /tmp/java_c/* root@operation-server:/home/ezdpl/apps/java_c/current/
说明:
ezdpl需要按照文件原始的目录结构保存每个文件,这样才能保证复制到目标服务器正确的路径下。cp -r –parent 可以带着父目录一起拷贝文件,正好满足这个需求。
有些生产环境需要准备一些空的目录结构,而生产服务器的目录里已经有了文件。上述的find 指令就可以从生产服务器里仅复制目录结构,忽略文件。
目录结构范例
级别 0,1
目录 描述 -------------- ------------------------------------------------ ezdpl ├── apps [级别 0] │ ├── common [级别 1, common并不是真正的应用,只是所有服务器都需要的脚本和配置文件] │ ├── web_a [级别 1, tomcat webapp a, 需要部署一台或多台] │ ├── web_b [级别 1, tomcat webapp b, 需要部署一台或多台] │ └── java_c [级别 1, java app c, 需要部署三台,每台需要配置多个IP地址] ├── ezdpl.sh [级别 0, 主脚本] ├── ezdpl_auto.sh [级别 0, 主脚本, 静默模式] └── README [级别 0, 不用解释吧? ;)]
级别 2
目录 描述 ------------------------------- ------------------------------------------------ common/ ├── 20150720 [级别2, 版本20150720(暂时空)] └── current [级别2, 当前版本] ├── etc │ ├── cron.daily │ │ └── ntp_client.sh [ntp 时间同步脚本] │ └── sysconfig │ ├── iptables │ └── static-routes ├── runme.sh [初始化脚本] └── tmp [需要独立安装的软件包] └── jdk-7u75-linux-x64.rpm web_a/ ├── 20150406 [级别2, 版本20150406] │ └── opt │ └── tomcat-web_a │ └── webapps [tomcat webapps] └── current [级别2, current version] ├── etc │ └── logrotate.d │ └── web_a ├── opt │ ├── logs │ │ └── web_a [web_a 的日志目录(在tomcat-web_a/conf/logging.properties里设置] │ └── tomcat-web_a │ ├── bin │ ├── conf │ ├── lib │ ├── LICENSE │ ├── NOTICE │ ├── RELEASE-NOTES │ ├── RUNNING.txt │ ├── temp │ ├── webapps │ └── work └── root └── bin [web_a的管理脚本] ├── showlog ├── shutdown_web_a └── start_web_a web_b/ (ommited) java_c/ ├── current │ ├── etc │ │ └── logrotate.d │ │ └── java_c │ ├── home │ │ └── operuser [java_c应用需要以普通用户执行] │ │ └── bin [java_c的管理脚本] │ │ ├── showlog │ │ ├── shutdown_java_c │ │ └── start_java_c │ ├── opt │ │ ├── logs │ │ │ └── java_c │ │ └── java_c │ │ ├── conf │ │ ├── lib │ │ ├── output │ │ └── java_c.jar │ └── runme.sh ├── java_c1 │ ├── etc │ │ └── sysconfig │ │ └── network-scripts [java_c 第一台服务器的ip配置文件若干] │ └── runme.sh ├── java_c2 │ ├── etc │ │ └── sysconfig │ │ └── network-scripts │ └── runme.sh └── java_c3 ├── etc │ └── sysconfig │ └── network-scripts └── runme.sh
主脚本 ezdpl.sh 只需要做以下工作:
* 复制指定目录下的所有文件到目标服务器,比如 ./apps/app_name/version
* 远程执行初始化脚本,比如 ./apps/app_name/version/runme.sh
* 可以指定目标服务器的用户名,默认是root
* 可根据需要远程重启目标服务器,默认不重启
ezdpl_auto.sh 跟ezdpl.sh 几乎一样,只是去掉了交互确认部分,适合批量部署。
主脚本:
ezdpl/ezdpl.sh
#!/bin/bash echo echo "ezdpl does things in a raw and simple way." echo "https://github.com/Panblack/ezdpl" echo echo "Will initialize a new target server." echo "Or deploy an app to the target server." echo "Or upgrade a running production server." echo "Usage: ./ezdpl.sh <ip address> <app/version> [reboot Y/N(N)] [username(root)]" echo "Init 10.1.1.1: ./ezdpl.sh 10.1.1.1 common/current" echo "Deploy web_a to 10.1.1.1: ./ezdpl.sh 10.1.1.1 web_a/current Y root" echo "Upgrade 10.1.1.2's app: ./ezdpl.sh 10.1.1.2 java_c/20150720 N" echo "Upgrade 10.1.1.2's conf: ./ezdpl.sh 10.1.1.2 java_c/java_c2 N" echo # Confirmation read -p "Will overwrite configuration files or app on $1. Enter Y to continue: " if [ "$REPLY" != "Y" ]; then echo "Exit" exit 0 fi read -p "Are you sure? Enter Y to continue: " if [ "$REPLY" != "Y" ]; then echo "Exit" exit 0 fi # variables _ipaddress=$1 _app_version=$2 if [ -n "$3" ]; then _reboot=$3 fi if [ -n "$4" ]; then _username=$4 else _username="root" fi # Check if [ ! -d "./apps/$_app_version" ]; then echo echo "There is no $_app_version configured here !" exit 1 fi chkaccess=`ssh $_username@$_ipaddress ls -d /opt` if [ ! -n "$chkaccess" ]; then echo echo "$_ipaddress is not reachable. " exit 1 fi # Start copy app/version scp -r ./apps/$_app_version/* $_username@$_ipaddress:/ echo "./apps/$_app_version/* copied." # Run runme.sh on the target server if [ -f "./apps/$_app_version/runme.sh" ]; then ssh $_username@$_ipaddress sh /runme.sh echo "$_username@$_ipaddress:/runme.sh executed." #ssh $_username@$_ipaddress /bin/rm /runme.sh #echo "$_username@$_ipaddress:/runme.sh deleted." fi # Reboot target server. if [ "$_reboot" = "Y" ]; then echo echo "Target server will reboot..." echo ssh $_username@$_ipaddress reboot fi
runme.sh 范例
ezdpl/apps/common/current/runme.sh
#!/bin/bash #make it your script #set -e # /etc/profile /bin/cp /etc/profile /etc/profile.bak # Turn off mail check chkmailcheck=$(cat /etc/profile |grep "unset MAILCHECK"|grep -v "#") if [ ! -n "$chkmailcheck" ]; then echo "unset MAILCHECK" >> /etc/profile fi # make vim default chkvim=$(cat /etc/profile |grep "alias vi='vim'"|grep -v "#") if [ ! -n "$chkvim" ]; then echo "alias vi='vim'" >> /etc/profile fi # set LANG chklang=$(cat /etc/profile |grep "export LANG=en_US.UTF-8"|grep -v "#") if [ ! -n "$chklang" ]; then echo "export LANG=en_US.UTF-8" >> /etc/profile fi echo echo "/etc/profile modified." echo # ll with long-iso date format /bin/cp /etc/profile.d/colorls.sh /etc/profile.d/colorls.sh.bak chkll=$(cat /etc/profile.d/colorls.sh |grep "alias ll='ls -l --color=auto --time-style=long-iso'"|grep -v "#") if [ ! -n "$chkll" ]; then echo "alias ll='ls -l --color=auto --time-style=long-iso' 2>/dev/null" >> /etc/profile.d/colorls.sh fi echo echo "/etc/profile.d/colorls.sh modified." echo # Selinux sed 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config -i echo echo "/etc/selinux/config modified." echo # disable cron mail sed 's/MAILTO=root/MAILTO=""/g' /etc/crontab -i echo echo "/etc/crontab modified." echo # install/reinstall jdk for x in $(rpm -qa|egrep "jdk|jre"); do rpm -e --nodeps $x done rpm -ivh /tmp/jdk-7u75-linux-x64.rpm echo echo "jdk installed/reinstalled." echo # install necessary packages: yum clean all yum install zip unzip man vim tree ntpdate sysstat wget gcc tcpdump telnet bind-utils -y echo echo "necessary packages installed. " echo # Finish source /etc/profile setenforce 0 chkconfig ip6tables off chkconfig crond on chkconfig iptables on /etc/init.d/crond restart /etc/init.d/iptables restart /etc/init.d/network restart echo echo "services restarted." echo
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/34258.html