ansible 个人使用习惯笔记
语法检查别名
alias ansible-playbook-check='ansible-playbook --syntax-check'查看模块帮助,例如查看file模块的帮助文档
ansible-doc file查看可用模块:自动进入less模块,可/搜索
ansible-doc -l 语法检查别名
alias ansible-playbook-check='ansible-playbook --syntax-check'查看模块帮助,例如查看file模块的帮助文档
ansible-doc file查看可用模块:自动进入less模块,可/搜索
ansible-doc -l 你可能会遇到的问题:
使用ansible-playbook的时候,ssh无法链接前台服务器
点击【高级】,为命令增加附加参数,使用--become-user root 即使用root用户执行playbook命令
Additional parameters: --become-user root
另外,添加好ssh无密码访问后,还需要切换到jenkins用户连接一次服务器,因为第一次连接时会让用户输入yes后才能连接上,所以需要操作一次,成功连接后即可使用了
sudo -u jenkins ssh root@192.168.1.10
================= 本文开始 =============
创建自定义项目:
选择 This project is parameterized (这个项目是参数化的),参数如下:
####Choice Parameter
名称
Status
选项
Deploy
Rollback
描述
Deploy:发布
Rollback:回滚
####String Parameter
名称
Version
默认值
0
描述
发布版本序号
同步项目代码前备份:
case $Status in
# Deploy)
# echo "Status:$Status"
# path="${WORKSPACE}/../${JOB_NAME}_bak/${BUILD_NUMBER}" #创建每次要备份的目录
# if [ -d $path ];
# then
# echo "The files is already exists "
# else
# mkdir -p $path
# fi
# rsync -r --exclude=".git" ${WORKSPACE}/ $path/ #将构建工作空间文件备份到文件夹
# echo "Copy code to ${path} Completing!"
# ;;
Rollback)
echo "Status:$Status"
echo "Version:$Version"
if [ $Version -lt 1 ];then
echo "Version val is error"
exit 1
fi
path="${WORKSPACE}/../${JOB_NAME}_bak/$Version" #备份目录
if [ ! -d $path ];then
echo "Bak dir not exists: $path"
exit 2
fi
#清除工作空间中除了.git文件夹的所有文件
find ${WORKSPACE}/ ! -regex .*\.git.* -empty -delete
rsync -r --exclude=".git" ${path}/ ${WORKSPACE}/ #将备份拷贝到构建工作空间
echo "Copy bak code ${path} to ${WORKSPACE} Completing!"
;;
*)
exit
;;
esac同步代码过程...
例子使用了ansible-playbook将代码同步到远程WEB服务器:
全局环境变量设置:
全局属性
Environment variables
键值对列表
键 PLAY_BOOK_EXCLUDE_FILE
值 /etc/ansible/playbook/deploy.excludejenkins安装好ansible插件,配置一下ansible插件的命令路径: 配置好两个命令ansible(本例未使用)和ansible-playbook
构建设置:这里使用了一个自定义的环境变量(jenkins全局管理里面配置的PLAY_BOOK_EXCLUDE_FILE,项目同步时忽略的目录和文件可以写到这个文件里)
Ansible installation ansible-playbook
Playbook path /etc/ansible/playbook/deploy.yml
Inventory Do not specify Inventory
Host subset dev-web test
Number of parallel processes 5
Extra Variables
Key srcdir
Value ${WORKSPACE}/
Key destdir
Value /www/wwwroot/houtai111/
Key opts
Value --exclude-from=${PLAY_BOOK_EXCLUDE_FILE}同步代码以后备份本次代码
case $Status in
Deploy)
echo "Status:$Status"
path="${WORKSPACE}/../${JOB_NAME}_bak/${BUILD_NUMBER}" #创建每次要备份的目录
if [ -d $path ];
then
echo "The files is already exists "
else
mkdir -p $path
fi
rsync -r --exclude=".git" ${WORKSPACE}/ $path/ #将构建工作空间文件备份到文件夹
echo "Copy code to ${path} Completing!"
;;
# Rollback)
# echo "Status:$Status"
# echo "Version:$Version"
#
# if [ $Version -lt 1 ];then
# echo "Version val is error"
# exit 1
# fi
#
# path="${WORKSPACE}/../${JOB_NAME}_bak/$Version" #备份目录
# if [ ! -d $path ];then
# echo "Bak dir not exists: $path"
# exit 2
# fi
#
# rsync -r --exclude=".git" ${path}/ ${WORKSPACE}/ #将备份拷贝到构建工作空间
# echo "Copy bak code ${path} to ${WORKSPACE} Completing!"
# ;;
*)
exit
;;
esac最后清理多余的备份,只保留最近的备份数量
ReservedNum=5 #保留文件数
FileDir="${WORKSPACE}/../${JOB_NAME}_bak"
date=$(date "+%Y%m%d-%H%M%S")
cd $FileDir #进入备份目录
FileNum=$(ls -l | grep '^d' | wc -l) #当前有几个文件夹,即几个备份
while(( $FileNum > $ReservedNum))
do
OldFile=$(ls -rt | head -1) #获取最旧的那个备份文件夹
echo $date "Delete File:"$OldFile
rm -rf $FileDir/$OldFile
let "FileNum--"
done 构建项目的时候就会有选择:Deploy 还是 Rollback, 选择Rollback的话,version 填写 发布的序号即可使用相应的备份数据
playbook
- hosts: test,online
remote_user: root
tasks:
- name: deploy code to remote server
synchronize:
src: '{{ srcdir }}'
dest: '{{ destdir }}'
mode: push
dirs: yes
owner: no
group: no
copy_links: no
delete: no
rsync_opts: '{{opts}}'
- name: copy files if not existing, and delete extraneous files
synchronize:
src: '{{ srcdir }}/{{ item }}'
dest: '{{ destdir }}/{{ item }}'
mode: push
dirs: yes
owner: no
group: no
copy_links: no
delete: yes
rsync_opts: '--ignore-existing'
with_items:
- common/coreCss/
- common/coreJs/
- common/css/
- common/js/
- pay/alipayMobile/alipay.config.php
- pay/alipayPC/alipay.config.php
- pay/singleTradeQuery/alipay.config.php
- wxpay/lib/WxPay.Config.php
- name: change files mode
file:
path: '{{ destdir }}/{{ item.0 }}'
mode: '{{ item.1 }}'
with_list:
- ['protected/yiic', '0755']
deploy.exclude
.git
.idea
.user.ini
lextab.py
yacctab.py
assets
attachments
node_modules
protected/runtime
pay/alipayMobile/alipay.config.php
pay/alipayPC/alipay.config.php
pay/singleTradeQuery/alipay.config.php
wxpay/lib/WxPay.Config.php
ansible hosts
[test]
192.168.1.100
[online]
web1 ansible_ssh_host=192.168.1.101 ansible_ssh_port=22
web2 ansible_ssh_host=192.168.1.102 ansible_ssh_port=22 总结:
squash 使用:squash merge
在使用 git 的过程中,可能你遇到过想要合并多个 commit 为一个,然后很多人会告诉你用 git commit --amend,然后你发现里面有你的多个 commit 历史,你可以通过 pick 选择,squash 合并等等。同样得,merge 的时候也可以这么干,你只需要这么简单的两步:
你会发现,在 master 分支上居然有未提交的修改,然后你就需要在 master 上主动提交了修改,注意,这里是你 commit 的,也就是改变了 commit 的 author。
rebase 使用
但是,作为处女座的程序员肯定是不能忍受目前的情况的,因为我们既想合并 commits,又想保留作者的信息,那么有没有什么好办法呢?肯定是有的啦,这个时候我们可以尝试一下 rebase,操作步骤是这样的:
这里完成了第二步之后我想你应该大概知道发生了什么事了,我们在 devel 里面对照 master 进行了变基,所谓的变基其实就是找到两个分支共同的祖先,然后在当前分支上合并从共同祖先到现在的所有 commit,所以我们在第二步的时候会选择怎么处理这些 commit,然后我们就得到了一个从公共commit 到现在的单个 commit,这个时候别人讲我们这个 commit 合并到 master 也只会在 master 上留下一个 commit 记录,就像这样:
虽然这个 commit history 线看上去很不错,而且也比较符合实际情况,但是我们需要注意到的有点就是分支上的开发者需要自己执行变基操作,从而导致他的原始 commit history 变化了(可以理解成被合并了)。
playbook中可以写多种循环:
with_list
with_items
with_indexed_items
with_flattened
with_together
with_dict
with_sequence
with_subelements
with_nested / with_cartesian
with_random_choice列表 with_list
这个例子会分别执行['protected/yiic1', '0755'], ['protected/yiic2', '0766'],['protected/yiic3', '0777']
- name: change files mode
file:
path: '{{ destdir }}/{{ item.0 }}'
mode: '{{ item.1 }}'
with_list:
- ['protected/yiic1', '0755']
- ['protected/yiic2', '0766']
- ['protected/yiic3', '0777']标准循环(with_items):
注意例2的结果将会分别执行1,2,3,'a','b'
#例1
- name: add several users
user: name={{ item }} state=present groups=wheel
with_items:
- testuser1
- testuser2
#例2
- name: add several users
user: name={{ item }} state=present groups=wheel
with_items:
- [1,2,3]
- ['b','c']嵌套循环(with_nested / with_cartesian):可以实现 mkdir -p /testdir/testdir/{a,b,c}/{test1,test2} 这样的效果
- file:
state: directory
path: "/testdir/testdir/{{ item.0 }}/{{ item.1 }}"
with_nested:
- [ a, b, c ]
- [ test1, test2 ]对哈希表使用循环
---
users:
alice:
name: Alice Appleworth
telephone: 123-456-7890
bob:
name: Bob Bananarama
telephone: 987-654-3210
...
tasks:
- name: Print phone records
debug: msg="User {{ item.key }} is {{ item.value.name }} ({{ item.value.telephone }})"
with_dict: "{{users}}"对文件列表使用循环
---
- hosts: all
tasks:
# first ensure our target directory exists
- file: dest=/etc/fooapp state=directory
# copy each file over that matches the given pattern
- copy: src={{ item }} dest=/etc/fooapp/ owner=root mode=600
with_fileglob:
- /playbooks/files/fooapp/*对并行数据集使用循环(一个数组对应另一个数组)
---
alpha: [ 'a', 'b', 'c', 'd' ]
numbers: [ 1, 2, 3, 4 ]
#如果你想得到’(a, 1)’和’(b, 2)’之类的集合.可以使用’with_together’:
tasks:
- debug: msg="{{ item.0 }} and {{ item.1 }}"
with_together:
- "{{alpha}}"
- "{{numbers}}"对子元素使用循环
---
users:
- name: alice
authorized:
- /tmp/alice/onekey.pub
- /tmp/alice/twokey.pub
mysql:
password: mysql-password
hosts:
- "%"
- "127.0.0.1"
- "::1"
- "localhost"
privs:
- "*.*:SELECT"
- "DB1.*:ALL"
- name: bob
authorized:
- /tmp/bob/id_rsa.pub
mysql:
password: other-mysql-password
hosts:
- "db1"
privs:
- "*.*:SELECT"
- "DB2.*:ALL"
#那么可以这样实现:
- user: name={{ item.name }} state=present generate_ssh_key=yes
with_items: "{{users}}"
- authorized_key: "user={{ item.0.name }} key='{{ lookup('file', item.1) }}'"
with_subelements:
- users
- authorized
#根据mysql hosts以及预先给定的privs subkey列表,我们也可以在嵌套的subkey中迭代列表:
- name: Setup MySQL users
mysql_user: name={{ item.0.user }} password={{ item.0.mysql.password }} host={{ item.1 }} priv={{ item.0.mysql.privs | join('/') }}
with_subelements:
- users
- mysql.hosts对整数序列使用循环
with_sequence 可以以升序数字顺序生成一组序列.你可以指定起始值、终止值,以及一个可选的步长值.
指定参数时也可以使用key=value这种键值对的方式.如果采用这种方式,’format’是一个可打印的字符串.
数字值可以被指定为10进制,16进制(0x3f8)或者八进制(0600).负数则不受支持.请看以下示例:
---
- hosts: all
tasks:
# create groups
- group: name=evens state=present
- group: name=odds state=present
# create some test users
- user: name={{ item }} state=present groups=evens
with_sequence: start=0 end=32 format=testuser%02x
# create a series of directories with even numbers for some reason
- file: dest=/var/stuff/{{ item }} state=directory
with_sequence: start=4 end=16 stride=2
# a simpler way to use the sequence plugin
# create 4 groups
- group: name=group{{ item }} state=present
with_sequence: count=4随机选择
‘random_choice’功能可以用来随机获取一些值.它并不是负载均衡器(已经有相关的模块了).它有时可以用作一个简化版的负载均衡器,比如作为条件判断:
- debug: msg={{ item }}
with_random_choice:
- "go through the door"
- "drink from the goblet"
- "press the red button"
- "do nothing"Do-Until循环
有时你想重试一个任务直到达到某个条件.比如下面这个例子:
- action: shell /usr/bin/foo
register: result
until: result.stdout.find("all systems go") != -1
retries: 5
delay: 10上面的例子递归运行shell模块,直到模块结果中的stdout输出中包含”all systems go”字符串,或者该任务按照10秒的延迟重试超过5次.”retries”和”delay”的默认值分别是3和5.
该任务返回最后一个任务返回的结果.单次重试的结果可以使用-vv选项来查看. 被注册的变量会有一个新的属性’attempts’,值为该任务重试的次数.
查找第一个匹配的文件
这其实不是一个循环,但和循环很相似.如果你想引用一个文件,而该文件是从一组文件中根据给定条件匹配出来的.这组文件中部分文件名由变量拼接而成.针对该场景你可以这样做:
- name: INTERFACES | Create Ansible header for /etc/network/interfaces
template: src={{ item }} dest=/etc/foo.conf
with_first_found:
- "{{ansible_virtualization_type}}_foo.conf"
- "default_foo.conf"该功能还有一个更完整的版本,可以配置搜索路径.请看以下示例:
- name: some configuration template
template: src={{ item }} dest=/etc/file.cfg mode=0444 owner=root group=root
with_first_found:
- files:
- "{{inventory_hostname}}/etc/file.cfg"
paths:
- ../../../templates.overwrites
- ../../../templates
- files:
- etc/file.cfg
paths:
- templates迭代程序的执行结果
有时你想执行一个程序,而且按行循环该程序的输出.Ansible提供了一个优雅的方式来实现这一点.但请记住,该功能始终在控制机上执行,而不是本地机器:
- name: Example of looping over a command result
shell: /usr/bin/frobnicate {{ item }}
with_lines: /usr/bin/frobnications_per_host --param {{ inventory_hostname }}好吧,这好像有点随意.事实上,如果你在做一些与inventory有关的事情,比如你想编写一个动态的inventory源(参见 动态 Inventory),那么借助该功能能够快速实现.
如果你想远程执行命令,那么以上方法则不行.但你可以这样写:
- name: Example of looping over a REMOTE command result
shell: /usr/bin/something
register: command_result
- name: Do something with each result
shell: /usr/bin/something_else --param {{ item }}
with_items: "{{command_result.stdout_lines}}"使用索引循环列表
如果你想循环一个列表,同时得到一个数字索引来标明你当前处于列表什么位置,那么你可以这样做.虽然该方法不太常用:
- name: indexed loop demo
debug: msg="at array position {{ item.0 }} there is a value {{ item.1 }}"
with_indexed_items: "{{some_list}}"循环配置文件
ini插件可以使用正则表达式来获取一组键值对.因此,我们可以遍历该集合.以下是我们使用的ini文件:
[section1]
value1=section1/value1
value2=section1/value2
[section2]
value1=section2/value1
value2=section2/value2以下是使用 with_ini 的例子:
- debug: msg="{{item}}"
with_ini: value[1-2] section=section1 file=lookup.ini re=true