Author: 本末丶
上一篇中,我们描述了如何借助Ansible来持续发布spring boot/cloud项目,也演示了如何基于jenkins做代码回滚,后面想想还是有不少臃肿和不好管理的地方,又做了一些优化跟备份回滚策略的调整,在这篇文章中,我们可以看到做了优化的一些地方,以及回滚策略的调整,不过本篇将以Tomcat为容器的项目作为演示
发布流程预览:
规范与标准
下面是规划的一些标准(非强制,根据自己实际情况调整)
- 应用名称:
{应用类型}-{端口}-{应用名称}or{类型}-{应用名称}, 例如:web-8080-nc,web-8082-wechat(至于为什么要加端口信息,是因为一台机器可能有N个实例,为了避免端口冲突,将端口描述代入了应用名中) - 日志路径:
/log/web,例如:/log/web/web-8080-gateway - 代码路径:
/data/,例如:/data/web-8080-gateway - Tomcat安装路径:
/usr/local/tomcat - 实例路径:
/usr/local/tomcat/{应用名称} - Jenkins job命名: {
环境}_{项目分组}_{应用名称},如:TEST_GROUP1_web-8080-nc - 应用配置:存放于git中,建立了各个环境相应的目录,环境目录下对应应用名称的同名文件,如:
git@192.168.1.24:devops-conf/conf.git
|
|__UAT
| |__web-8080-nc
| |__web-8081-wechat
|
|__STG
| |__web-8080-nc
| |__web-8081-wechat
... ...
部署环境
1.版本环境
Ansible版本:2.6+
- Tomcat: 7+
- Jenkins:2.107.1
- Linux: Cent0S 6+
2. Jenkins安装插件
- Ansible plugin: 执行Ansible所需插件。
- AnsiColor:彩色输出,非必须
- Build With Parameters:参数化构建需要
- Git plugin:git需要
- JDK Parameter Plugin:自己按需吧
- Mask Passwords Plugin:参数化构建,加密密码类参数,非必须
- Readonly Parameter plugin:参数化构建里的,只读参数选项
- Active Choices Plug-in: 动态参数插件,发布不会用到,后面会介绍,有奇用
- Run Selector Plugin:参数化构建,选择插件
- Git Parameter Plug-In:git分支选择插件,非必要
发布任务配置
1. Jenkins Job配置
SVN拉取配置,没啥好说的
maven构建配置
Ansible插件配置
2. Ansible Role配置
1)代码结构
playbooks └──test-tomcat-deploy.yml # 入口文件 roles └──tomcat-deploy-test ├── defaults │ └── main.yml # 默认变量 ├── files │ ├── conf # 实例配置文件 │ │ ├── catalina.policy │ │ ├── catalina.properties │ │ ├── context.xml │ │ ├── logging.properties │ │ ├── tomcat-users.xml │ │ ├── tomcat-users.xsd │ │ └── web.xml │ └── tomcat.tar.gz # tomcat安装文件(没做任何调整,就是改名成tomcat后压缩了一下) ├── handlers │ └── main.yml # handlers任务 ├── tasks │ ├── backup.yml # 备份任务 │ ├── commons.yml # 一般任务 │ ├── deploy.yml # 部署任务 │ ├── init.yml # 初始化任务 │ └── main.yml # 主文件 └── templates ├── catalina.sh.j2 # 启动脚本 ├── env.j2 # 对于实例的描述文件,非必要 ├── server.xml.j2 # 实例的server.xml配置 └── systemd.service.j2 # systemd服务脚本
2)Role配置文件说明
①.playbooks/test-tomcat-deploy.yml
---
- hosts: target
roles:
- { role: tomcat-deploy-test, tags: deploy }②.defaults/main.yml
---
# base info
# JOB_NAME等信息直接从环境变量读取,而不是之前那样通过exra vars导入,少了很多不必要的参数填写
JOB_NAME: "{{ lookup('env','JOB_NAME') }}"
TOMCAT_HOME: "/usr/share/tomcat"
# 将JOB_NAME切割出各个信息
PROJECT: "{{ JOB_NAME.split('_')[-1] }}"
CODE_DEPTH_PATH: "{{ code_depth_path | default('') }}"
PROJECT_BASE: "/data/{{ PROJECT }}"
ENV: "{{ JOB_NAME.split('_')[0] }}"
# project info
project:
public:
JAVA_HOME: "{{ java_home | default('') }}"
GIT_CONF_REPO: "git@192.168.1.24:devops/conf.git"
JAVA_OPTS: "{{ lookup('env','JAVA_OPTS') | default('-server -Xms2048M -Xmx2048M') }}"
local:
# 备份信息日志路径
deploy_release_log: "/data/deploy_release_log/{{ ENV }}/{{ PROJECT }}"
# 构建后的代码路径
CODE_PATH: "{{ local_code_path | default('') }}"
target:
# 实例相关配置
CATALINA_HOME: "{{ TOMCAT_HOME }}"
CATALINA_BASE: "/usr/local/tomcat/{{ PROJECT }}"
CATALINA_LOGBASE: "/usr/local/tomcat/{{ PROJECT }}/logs"
#tomcat虚拟路径,默认为空
TOMCAT_VIRTUAL_PATH: "{{ lookup('env','tomcat_virtual_path') }}"
CODE_PATH: "{{ PROJECT_BASE }}/{{ CODE_DEPTH_PATH }}"
TOMCAT_USER: "{{ tomcat_user | default('tomcat') }}"
TOMCAT_PORT: "{{ PROJECT.split('-')[1] }}"
# 备份目录
HISTORY_ARCHIVR_DIR: "/data/deploy_release_library/{{ PROJECT }}"
# 应用日志(不是必须的)
LOGPATH: "/log/{{ PROJECT.split('-')[0] }}/{{ PROJECT }}"
③files/conf(直接从tomcat二进制包里的conf原样复制过来即可)
④tasks/main.yml
--- # 打印变量信息 - name: show project info debug: var=project failed_when: (project is not defined) # 初始化实例 - include_tasks: "init.yml" # 一般任务 - include_tasks: "commons.yml" # 备份任务,存在代码才备份 - include_tasks: "backup.yml" when: (code_status.rc == 0) # 发布任务 - include_tasks: "deploy.yml"
⑤ tasks/init.yml
---
# 创建运行账户
- name: Create {{ project.target.TOMCAT_USER }} user
user: name={{ project.target.TOMCAT_USER }}
# 检查tomcat是否安装
- name: Verify that tomcat installed
command: "{{ TOMCAT_HOME }}/bin/catalina.sh version"
environment:
JAVA_HOME: "{{ project.public.JAVA_HOME }}"
register: check_install
failed_when: false
# 没装就直接解压过去
- name: Install tomcat
unarchive:
src: tomcat.tar.gz
dest: /usr/share
owner: "{{ project.target.TOMCAT_USER }}"
group: "{{ project.target.TOMCAT_USER }}"
when: check_install.rc != 0
# 创建实例目录接口(file循环我嫌慢,shell来的快)
- name: Create {{ PROJECT }} directory
shell: |
mkdir -p {{ project.target.CATALINA_BASE }}/{conf,work,bin,webapps,temp,logs,lib} {{ project.target.LOGPATH }} {{ project.target.CODE_PATH }} &>/dev/null
chown {{ project.target.TOMCAT_USER }}. -R {{ project.target.CATALINA_BASE }} {{ project.target.LOGPATH }} {{ project.target.CODE_PATH }}
# 推送实例模板文件
- name: Push {{ PROJECT }} templates
template:
src: "{{ item.src }}"
dest: "{{ item.dest }}"
mode: "{{ item.mode }}"
owner: "{{ project.target.TOMCAT_USER }}"
group: "{{ project.target.TOMCAT_USER }}"
loop:
- { src: server.xml.j2, dest: "{{ project.target.CATALINA_BASE }}/conf/server.xml", mode: 644 }
- { src: catalina.sh.j2, dest: "{{ project.target.CATALINA_BASE }}/bin/catalina.sh", mode: 'u=rwx,g=rx,o=r' }
- { src: env.j2, dest: "{{ project.target.CATALINA_BASE }}/env", mode: 644 }
# 推送实例一般配置文件
- name: Push Tomcat config
synchronize:
src: conf/
dest: "{{ project.target.CATALINA_BASE }}/conf"
# CentOS7使用systemd管理服务
- name: Copy Systemd script
template:
src: systemd.service.j2
dest: /etc/systemd/system/{{ PROJECT }}.service
mode: 0644
when: ansible_distribution_major_version|int >= 7
# CentOS6使用SysV脚本
- block:
- name: Link to Sysvinit
file:
src: "{{ project.target.CATALINA_BASE }}/bin/catalina.sh"
dest: "/etc/init.d/{{ PROJECT }}"
state: link
force: yes
- name: Add to chkconfig
shell: chkconfig --add {{ PROJECT }}
when: ansible_distribution_major_version|int < 7
⑥tasks/commons.yml
---
# 设置变量,time相关的不要放入defaults里,因为include是动态取的,会有变化
- set_fact:
deploy_time: "{{ lookup('pipe','date +%Y%m%d%H') }}"
# 这里使用lookup获取本地时间,而不是strftime去取,因为客户端时间可能不一致
git_conf_tmp_path: "/tmp/.config/{{ lookup('pipe', 'date +%s') }}"
# 拉取git里存放的配置到临时目录
- name: Git conf
git:
repo: "{{ project.public.GIT_CONF_REPO }}"
dest: "{{ git_conf_tmp_path }}"
ssh_opts: '-o StrictHostKeyChecking=no'
delegate_to: localhost
run_once: true
# 检查应用代码是否为空
- name: Verify remote code exists
shell: ls {{ project.target.CODE_PATH }}/* &> /dev/null
register: code_status
failed_when: false
⑦tasks/backup.yml
---
# 创建备份目录
- name: Create Histroy Archive Directory
file:
dest: "{{ project.target.HISTORY_ARCHIVR_DIR }}/{{ deploy_time }}"
state: directory
owner: "{{ project.target.TOMCAT_USER }}"
group: "{{ project.target.TOMCAT_USER }}"
recurse: yes
# 压缩文件到备份目录下
- block:
- name: Compress and backup files
archive:
path:
- "{{ PROJECT_BASE }}/*"
dest: "{{ HISTORY_ARCHIVR_DIR }}/{{ deploy_time }}/{{ PROJECT }}.zip"
exclude_path:
- "{{ PROJECT_BASE }}/log"
- "{{ PROJECT_BASE }}/logs"
format: zip
owner: "{{ RUN_USER }}"
group: "{{ RUN_USER }}"
- name: Write Deploy release log
blockinfile:
path: "{{ project.local.deploy_release_log }}/{{ deploy_time }}"
block: |-
{{ release_log | to_nice_json(indent=2) }}
create: yes
delegate_to: localhost
run_once: true
vars:
release_log:
target: "{{ ansible_play_hosts | join(':') }}"
project: "{{ PROJECT }}"
run_user: "{{ RUN_USER }}"
backup_dir: "{{ HISTORY_ARCHIVR_DIR }}/{{ deploy_time }}"
backup_file: "{{ HISTORY_ARCHIVR_DIR }}/{{ deploy_time }}/{{ PROJECT }}.zip"
project_dir: "{{ PROJECT_BASE }}"
backup_time: "{{ deploy_time }}"
env: "{{ ENV }}"
# 备份该时间段的第一次,一小时内的不重复备份,防止破坏备份文件稳定性
when: not lookup('pipe','ls ' + project.local.deploy_release_log + '/' + deploy_time + ' &> /dev/null', errors='ignore')
⑧tasks/deploy.yml
---
# 同步构建后的代码
- name: "Sync {{ project.local.CODE_PATH }} >> {{ project.target.CODE_PATH }}"
synchronize:
src: "{{ project.local.CODE_PATH }}/"
dest: "{{ project.target.CODE_PATH }}"
delete: yes
# 同步git拉取到临时目录的配置文件,同事触发handler,不同系统触发不同的hander任务重启
- name: "Sync {{ git_conf_tmp_path }}/{{ ENV }}/{{ PROJECT }}/ >> {{ PROJECT_BASE }}"
synchronize:
src: "{{ git_conf_tmp_path }}/{{ ENV }}/{{ PROJECT }}/"
dest: "{{ PROJECT_BASE }}"
notify:
- "{{ ansible_distribution_major_version }} Restart Tomcat"
# 设置属主
- name: Set owner >> "{{ project.target.TOMCAT_USER }}"
file:
path: "{{ PROJECT_BASE }}"
recurse: yes
state: directory
owner: "{{ project.target.TOMCAT_USER }}"
group: "{{ project.target.TOMCAT_USER }}"
# 删除临时文件
- name: Remove local config
file:
path: "{{ git_conf_tmp_path }}"
state: absent
delegate_to: localhost
run_once: true
⑨handlers/main.yml
---
- name: 7 Restart Tomcat
systemd: name={{ PROJECT }} state=restarted enabled=yes daemon_reload=yes
# 因为我们是root过去的,6指定下become到运行账户启动
- name: 6 Restart Tomcat
service: name={{ PROJECT }} pattern=/etc/init.d/{{ PROJECT }} state=restarted sleep=5 enabled=yes
become_user: "{{ project.target.TOMCAT_USER }}"
become: yes
⑩templates/server.xml.j2
<?xml version='1.0' encoding='utf-8'?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!-- Note: A "Server" is not itself a "Container", so you may not
define subcomponents such as "Valves" at this level.
Documentation at /docs/config/server.html
-->
<Server port="{{ project.target.TOMCAT_PORT|int + 1000 }}" shutdown="SHUTDOWN">
<Listener className="org.apache.catalina.startup.VersionLoggerListener" />
<!-- Security listener. Documentation at /docs/config/listeners.html
<Listener className="org.apache.catalina.security.SecurityListener" />
-->
<!--APR library loader. Documentation at /docs/apr.html -->
<Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="off" />
<!-- Prevent memory leaks due to use of particular java/javax APIs-->
<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
<Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />
<!-- Global JNDI resources
Documentation at /docs/jndi-resources-howto.html
-->
<GlobalNamingResources>
<!-- Editable user database that can also be used by
UserDatabaseRealm to authenticate users
-->
<Resource name="UserDatabase" auth="Container"
type="org.apache.catalina.UserDatabase"
description="User database that can be updated and saved"
factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
pathname="conf/tomcat-users.xml" />
</GlobalNamingResources>
<!-- A "Service" is a collection of one or more "Connectors" that share
a single "Container" Note: A "Service" is not itself a "Container",
so you may not define subcomponents such as "Valves" at this level.
Documentation at /docs/config/service.html
-->
<Service name="Catalina">
<!--The connectors can use a shared executor, you can define one or more named thread pools-->
<!--
<Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
maxThreads="150" minSpareThreads="4"/>
-->
<!-- A "Connector" represents an endpoint by which requests are received
and responses are returned. Documentation at :
Java HTTP Connector: /docs/config/http.html (blocking & non-blocking)
Java AJP Connector: /docs/config/ajp.html
APR (HTTP/AJP) Connector: /docs/apr.html
Define a non-SSL/TLS HTTP/1.1 Connector on port 8080
-->
<Connector port="{{ project.target.TOMCAT_PORT }}"
protocol="org.apache.coyote.http11.Http11NioProtocol"
maxThreads="3000" minSpareThreads="500"
acceptCount="1000" maxKeepAliveRequests="1"
connectionTimeout="20000" enableLookups="false"
URIEncoding="UTF-8" redirectPort="8443" />
<!-- A "Connector" using the shared thread pool-->
<!--
<Connector executor="tomcatThreadPool"
port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
-->
<!-- Define a SSL/TLS HTTP/1.1 Connector on port 8443
This connector uses the NIO implementation that requires the JSSE
style configuration. When using the APR/native implementation, the
OpenSSL style configuration is required as described in the APR/native
documentation -->
<!--
<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
clientAuth="false" sslProtocol="TLS" />
-->
<!-- Define an AJP 1.3 Connector on port 8009
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" /> -->
<!-- An Engine represents the entry point (within Catalina) that processes
every request. The Engine implementation for Tomcat stand alone
analyzes the HTTP headers included with the request, and passes them
on to the appropriate Host (virtual host).
Documentation at /docs/config/engine.html -->
<!-- You should set jvmRoute to support load-balancing via AJP ie :
<Engine name="Catalina" defaultHost="localhost" jvmRoute="jvm1">
-->
<Engine name="Catalina" defaultHost="localhost">
<!--For clustering, please take a look at documentation at:
/docs/cluster-howto.html (simple how to)
/docs/config/cluster.html (reference documentation) -->
<!--
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>
-->
<!-- Use the LockOutRealm to prevent attempts to guess user passwords
via a brute-force attack -->
<Realm className="org.apache.catalina.realm.LockOutRealm">
<!-- This Realm uses the UserDatabase configured in the global JNDI
resources under the key "UserDatabase". Any edits
that are performed against this UserDatabase are immediately
available for use by the Realm. -->
<Realm className="org.apache.catalina.realm.UserDatabaseRealm"
resourceName="UserDatabase"/>
</Realm>
<Host name="localhost" appBase="{{ PROJECT_BASE }}"
unpackWARs="true" autoDeploy="true">
<!-- SingleSignOn valve, share authentication between web applications
Documentation at: /docs/config/valve.html -->
<!--
<Valve className="org.apache.catalina.authenticator.SingleSignOn" />
-->
<!-- Access log processes all example.
Documentation at: /docs/config/valve.html
Note: The pattern used is equivalent to using pattern="common" -->
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="localhost_access_log" suffix=".txt"
pattern="%h %l %u %t "%r" %s %b" />
{#-
这是是虚拟路径的配置,只有指定了tomcat_virtual_path才生效,
默认TOMCAT_VIRTUAL_PATH为空,tomcat_vittual_path做为jenkins参数化构建传递,
格式为: /path:/docBase,比如,
项目名称为web-8080-static,代码路径为/data/web-8080-nc/static,那么格式如下:
/static:/static
多个路径格式为:
/static:/static,/nc:/nc
-#}
{% if project.target.TOMCAT_VIRTUAL_PATH != "" %}
{% for vpath in project.target.TOMCAT_VIRTUAL_PATH.split(',') %}
<Context path="{{ vpath.split(':')[0] }}" docBase="{{ PROJECT_BASE }}{{ vpath.split(':')[1] }}" reloadable="true" crossContext="true"></Context>
{% endfor %}
{% endif %}
<!--<Context path="" docBase="{{ PROJECT_BASE }}" reloadable="true" crossContext="true"></Context>-->
</Host>
</Engine>
</Service>
</Server>
⑫templates/catalina.sh.j2
#!/bin/bash
# Provides: {{ PROJECT }}
# chkconfig: - 55 25
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Start Tomcat.
# Description: Start the Tomcat servlet engine.
# Author: 本末丶
### END INIT INFO
# Source function library.
. /etc/rc.d/init.d/functions
program="{{ PROJECT }}"
export TOMCAT_USER="{{ project.target.TOMCAT_USER }}"
export CATALINA_PID="{{ project.target.CATALINA_BASE }}/bin/$program.pid"
export TOMCAT_HOME={{ TOMCAT_HOME }}
export CATALINA_HOME=$TOMCAT_HOME
export CATALINA_BASE={{ project.target.CATALINA_BASE }}
export CATALINA_LOGBASE={{ project.target.CATALINA_LOGBASE }}
export JAVA_OPTS="{{ project.public.JAVA_OPTS }} -Dcatalina.logbase=$CATALINA_LOGBASE -Djava.security.egd=file:/dev/./urandom"
{% if project.public.JAVA_HOME != '' %}
export JAVA_HOME={{ project.public.JAVA_HOME }}
{% else %}
source /etc/profile
{% endif %}
# Set Tomcat environment.
export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$CATALINA_HOME
export CATALINA_OUT=$CATALINA_LOGBASE/catalina.out
export PATH=$PATH:$JAVA_HOME/bin:/usr/bin:/usr/lib/bin
# locale环境,防止中文写日志乱码问题
export LANG=en_US.UTF-8
export LC_CTYPE="en_US.UTF-8"
export LC_NUMERIC="en_US.UTF-8"
export LC_TIME="en_US.UTF-8"
export LC_COLLATE="en_US.UTF-8"
export LC_MONETARY="en_US.UTF-8"
export LC_MESSAGES="en_US.UTF-8"
export LC_PAPER="en_US.UTF-8"
export LC_NAME="en_US.UTF-8"
export LC_ADDRESS="en_US.UTF-8"
export LC_TELEPHONE="en_US.UTF-8"
export LC_MEASUREMENT="en_US.UTF-8"
export LC_IDENTIFICATION="en_US.UTF-8"
export LC_ALL=
# cache
cache_dir="${CATALINA_BASE}/work"
# check --no-daemonize option
args=$2
# sctipt
catalinaScript="${TOMCAT_HOME}/bin/catalina.sh"
get_pid() {
ps -eo pid,cmd | grep java | grep "${CATALINA_BASE}" | grep -Pv "grep|python" | awk '{print $1}'
}
run_program() {
if [[ "${args}"x == "--no-daemonize"x ]];then
${catalinaScript} start 2>&1 | tee -a $CATALINA_OUT
tailf $CATALINA_OUT
else
nohup ${catalinaScript} start &>> $CATALINA_OUT
return $?
fi
}
run_or_not() {
pid=$(get_pid)
if [[ ! ${pid} ]];then
return 1
else
return 0
fi
}
start() {
run_or_not
if [[ $? -eq 0 ]];then
pid=$(get_pid)
success;echo -e "[\e[0;32m${pid}\e[0m] Tomcat ${program} is running..."
else
echo -n 'Start Tomcat.'
run_program
if [[ $? -eq 0 ]];then
sleep 5
pid=$(get_pid)
if [[ "$pid"x != x ]];then
flag=success
else
flag=failure
$flag;echo -e "Success Start Tomcat ${program}, but it exists.!"
return 1
fi
else
flag=failure
fi
$flag;echo -e "[\e[0;32m$pid\e[0m] Start Tomcat ${program}"
fi
}
stop() {
run_or_not
if [[ $? -eq 0 ]];then
${catalinaScript} stop |& tee -a $CATALINA_OUT
sleep 5
run_or_not
if [[ $? -eq 0 ]];then
pid=$(get_pid)
kill -9 $pid
echo -e "Stop Failed...Killing Process [\e[0;32m$pid\e[0m]..."
fi
success;echo -e "Stop Tomcat $program"
else
failure;echo -e "Tomcat $program is not running."
fi
}
status() {
run_or_not
if [[ $? -eq 0 ]];then
pid=$(get_pid)
success;echo -e "[\e[0;32m${pid}\e[0m] Tomcat $program is running..."
return 0
else
failure;echo -e "Tomcat $program not running."
return 1
fi
}
case $1 in
start)
start
;;
stop)
stop
;;
status)
status
;;
restart)
stop
start
;;
*)
echo "Usage: $0 {start [--no-daemonize]|stop|status|restart}"
return 1
esac
⑬templates/systemd.service.j2
[Unit]
Description={{ PROJECT }}
After=network.target
[Service]
ExecStart={{ project.target.CATALINA_BASE }}/bin/catalina.sh start --no-daemonize
ExecStop={{ project.target.CATALINA_BASE }}/bin/catalina.sh stop
#WorkingDirectory={{ project.target.CATALINA_BASE }}
#Restart=on-failure
#RestartSec=30
User={{ project.target.TOMCAT_USER }}
Group={{ project.target.TOMCAT_USER }}
[Install]
WantedBy=multi-user.target
⑮templates/env.j2(描述信息而已)
project_name="{{ PROJECT }}"
tomcat_port="{{ project.target.TOMCAT_PORT }}"
control_port="{{ project.target.TOMCAT_PORT|int + 1000 }}"
project_base="{{ PROJECT_BASE }}"
log_base="{{ project.target.CATALINA_LOGBASE }}"
last_update="{{ '%Y-%m-%d %H:%M' | strftime }}"
3) 发布演示。
大部分的工作都OK了,由于我们没有沿用之前jenins中账号密码的方式去验证,所以我们需要先做ssh key的信任,这里提供一个playbooks
ssh_keys.yml
---
- hosts: "{{ target }}"
gather_facts: false
tasks:
- name: Create user if not exists
user: name={{ luser }} shell=/bin/bash generate_ssh_key=yes
register: local
delegate_to: localhost
- name: Ensure remote user exists
user: name={{ ruser }} shell=/bin/bash
- name: Write key to authorized_keys
authorized_key:
user: "{{ ruser }}"
state: present
key: "{{ local.ssh_public_key }}"
manage_dir: yes运行方式:
ansible-playbook ssh_keys.yml -e 'target=你远程的服务器 luser=jenkins ruser=root' -u root -k # 其中target是你远程服务器的地址,luser是你jenkins运行账户,ruser是远程账户
发布预览(动图,PDF不会动,要动的自己看blog):
查看服务:
查看备份日志;
查看备份文件:
OK.发布相关的任务到此结束,后面会说说怎么做回滚。
未完待续...
没有帐号? 立即注册