ansible教程

安装ansible

yum方式安装

导入阿里云epel yum源

wget http://mirrors.aliyun.com/repo/Centos-7.repo
wget http://mirrors.aliyun.com/repo/epel-7.repo

安装repo

yum install ansible python2-pip

模块

authorized_key

管理用户authorized_keys实现免密登陆

参数 描述
comment 更改公钥注释
exclusive 添加或删除authorized_keys
key 指定公钥
path 指定authorized_keys路径
state 如果是present则创建,如果是absent则删除
user 指定用户名称

配置节点k8s用户互信

- name: config k8s user account
authorized_key:
user: k8s
key: "{{ lookup('file', '/home/k8s/.ssh/id_rsa.pub') }}"
exclusive: yes
state: present

command模块

参数 描述
creates 一个文件名,当该文件存在则命令不执行
free_form 要执行的Linux指令
chdir 在执行指令之前,先切换到该指定的目录
removes 一个文件名,如果文件不存在,则该选项不执行
state 如果是present则创建,如果是absent则删除
user 指定用户名称

copy模块

参数

参数 描述
src 源文件
dest 目标路径
backup 覆盖前是否备份原文件
owner 设置文件目录的属主
group 设置文件目录的属组
mode 设置文件目录的权限

cron模块

参数 描述
backup 对远程主机上原任务计划内容修改之前备份
day
hour 小时
minute 分钟
month
weekday
job 要执行的文件,依赖于state=present
name 该任务的描述
special_time 指定什么时候执行(参数:reboot、yearly、annually、monthly、weekly、daily、hourly)
state 确认该任务计划是创建还是删除
user 以哪个用户的身份执行

创建一个计划任务

- name: Create cron job
cron:
name: cron_test
minute: "*/3"
hour: "*"
day: "*"
month: "*"
weekday: "*"
job: "/usr/sbin/ntpdate cn.ntp.org.cn"

docker_container模块

参数 可选项 描述
command 容器启动时执行的命令可以是字符串,也可以是列表
hostname 容器hostname
image 容器镜像
name 容器名称
env 容器环境变量
network_mode bridge、host、none 容器的网络模式
pull 下载镜像到本地
read_only 挂载容器根文件系统为只读
restart 重启容器
restart_policy no、on-failure、always、unless-stopped 重启容器策略
state absent、present、stopped、started 容器运行状态
volume_driver volume driver
volumes 容器共享宿主机的目录,例如:volumes: /opt:container:/opt

创建容器

- name: start docker registry
docker_container:
name: registry
image: registry:2
ports:
- 4000:5000
- 80:80
state: started
restart_policy: always
volumes:
- /opt/t2cp:/var/lib/registry
- /etc/test:/etc/test

重启容器

- name: restart docker registry
docker_container:
name: registry
image: registry:2
state: restarted
restart: yes
ports: 4000:5000

file模块

参数 描述
group 定义文件/目录属组
owner 定义文件目录属主
mode 定义文件目录的权限
owner 设置文件目录的属主
path 定义文件目录的路径
recurse 递归设置文件的属性,只对目录有效
state 定义文件状态(state状态有三个选项directory:如果目录不存在则创建、touch:如果文件不存在则创建、absent:删除文件或目录)

fetch模块

从远程主机复制文件到本地

参数 描述
src 源文件
dest 目标文件
flat 如果dest的路径以/结尾保存在相对路径目录下

目标节点拉取配置文件到ansible节点

- name: copy ceph config to tmp dir
fetch:
src: /tmp/ceph.conf
dest: /tmp/ceph.conf
flat: yes

find模块

find模块可以帮助我们在远程主机查找符合条件的文件,类似与linux操作系统find命令。

参数 描述
paths 指定文件路径,可以指定多个路径,路径间用逗号隔开
recurse 当 recurse 参数设置为 yes 时,表示在指定目录中递归的查找文件
hidden 当 hidden 参数的值设置为 yes 时,才会查找隐藏文件
file_type 指定查找文件类型,可指定的文件类型有 any、directory、file、link 四种
contains 根据文章内容查找文件,此参数的值为一个正则表达式,find 模块会根据对应的正则表达式匹配文件内容。
age 根据时间范围查找文件,可以使用的单位有秒(s)、分(m)、时(h)、天(d)、星期(w)
age_stamp 文件的时间属性有三种,atime、ctime、mtime,当我们根据时间范围查找文件时,可以指定以哪个时间种类
size 指定查找文件的大小,可以使用的单位有 t、g、m、k、b

group模块

用户组管理

名称
name 用户名
state 创建或删除
groups 用户组
uid 用户UID
password 用户密码
home 指定家目录,需要createhomeyes
createhome 是否创建家目录
system 是否创建为系统用户
remove state=absent时,删除家目录
shell 指定用户shell环境

创建用户组

- name: Create a group named acai with a GID of 2016
group:
gid: 2016
name: acai

- name: Create user test_user and add to acai group
user:
name: test_user
groups: acai
state: present

lineinfile模块

该模块用于从一个文件中搜索一行,确保该行存在或删除该行。lineinfile模块主要用于改变一个文件的一行。如果想要改变文件中相似的多行,可以使用replace模块。如果想要插入/更新/删除一个行块,可以使用blockinfile模块。

参数 描述
backup 用于创建一个包含时间戳信息的备份文件。以便在错误的修改了文件的时候,能够找回原始的文件。
create 与state=present一起使用。如果指定了这个参数,当要修改的文件不存在的时候,会创建它。否则会报错。
dest 要修改的文件
insertbefore 当regexp不匹配文件中的任何行的时候,会将line参数所指定的行,插入到insertbefore所指定的正则表达式匹配的行中的最后一行的前面,当insertbefore所指定的正则表达式不匹配任何行时,会插入到文件的末尾
insertafter 与insertbefore类似,不同的是,insertbefore会将新行插入到其所指定的正则表达式匹配的行中的最后一行的前面,而insertafter是插入到后面。
line 要插入或者替换的行。如果设置了backrefs参数,那么line中可以包含 位置分组 或 命名分组,lineinfile模块会使用regexp捕获的分组填充它们。
mode 用来指定文件的权限,比如mode=0644 或 mode=’a+x’
owner 和 group 用来指定文件的属主 和 属组
regexp 用于搜索文件中的每一行的正则表达式。对于state=present,这个正则表达式所匹配的行中的最后一行会被替换;对于state=present,会删除所有匹配的行。
state 用于设置 新增或替换一行,还是删除行

删除password文件开头为root的行

- name: delete line for root in password
lineinfile:
dest: '/etc/password'
state: absent
regexp: '^root'

关闭selinux

- name: disable selinux
lineinfile:
dest: '/etc/selinux/config'
regexp: '^SELINUX=.*'
line: 'SELINUX=disabled'
state: present

添加hosts解析

- name: add hosts
lineinfile:
dest: '/etc/hosts'
line: '172.16.1.10\ttest'
state: present

get_url模块

下载文件到/tmp

- name: download file to /tmp directory
get_url:
url: 'http://mirrors.aliyun.com/centos/timestamp.txt'
dest: '/tmp'

mysql_db模块

导入sql

- name: import register.sql for harbor 
mysql_db:
name: "{{ mysql_db_name }}"
state: import
target: /tmp/registry.sql
when: inventory_hostname in groups['harbor_nodes'][0]

创建数据库

- name: create database for harbor
mysql_db:
name: "{{ mysql_db_name }}"
state: present
run_once: yes

mysql_user模块

参数 可选值 描述
append_privs 用户添加权限,不会覆盖原有权限
config_file 指定user和passwd配置文件
connect_timeout 连接数据库超时时间
host mysql的IP或是主机名称
login_host 登陆mysql的主机名称
login_password 登陆mysql的用户密码
login_user 登陆mysql的用户
state present/absent
name 用户名
password 密码
priv 访问权限

创建mysql远程用户

- name: create harbor remote user for mysql database
mysql_user:
name: "{{ mysql_harbor_user }}"
password: "{{ mysql_harbor_pass }}"
host: "%"
priv: "{{ mysql_db_name }}.*:ALL"
append_privs: "yes"
run_once: yes

systemd模块

systemd模块就是使用systemctl来管理centos7系统服务

参数名称 可选值 备注
name yes/no 服务名称
enabled yes/no 是否设置开机启动
state started、stopped、restarted、reload 对服务执行的动作

service模块

参数 描述
enabled 是否开机启动 yes/no
name 服务名称
runlevel 运行级别
sleep 如果执行了restarted,在stop和start之间沉睡几秒
state 对服务执行启动,停止,重启,重新加载等

启动apache服务设置开机自动启动

- name: startup apache service
service:
name: httpd
state: started
enabled: yes

stat模块

索引文件、目录的状态

参数 可选项 备注
path 文件、目录路径

返回值

参数 可选项 备注
atime 返回最后一次访问文件的时间
attributes 返回属性
exists 路径是否存在
ischr 返回是否为设备
isdir 返回是否为目录
islnk 返回是否为链接
isuid 返回uid
mode 返回文件权限
mtime 返回最后修改时间
readable 返回是否有可读权限
size 返回文件字节大小

template模块

template使用了Jinjia2格式作为文件模版,进行文档内变量的替换的模块。

参数 可选项 备注
backup yes/no
src 文件源地址
dest 文件目的地址
mode 设置远程节点上的template文件权限。类似Linux中chmod的用法
owner 设置远程节点上的template文件所属用户
group 设置远程节点上的的template文件的所属用户组

创建chrony.conf.j2模版

allow {{ cluster_network }}

在templates目录下创建chrony.conf.j2文件并替换以下变量
allow

代表是由ansible引入的一个变量,该变量可在group_vars目录下文件中调用,eg:
cat group_vars/all 
---
#k8s cluster api network
#eg: cluster_network : 192.168.1.0/24
cluster_network : 192.168.1.0/24

当ansible执行该任务后,被copy的配置文件会被替换为cluster_network变量的值。

user模块

参数 可选值 描述
append yes/no
comment
create_home yes/no
expires

wait_for模块

当我们启动一个服务或是执行某条shell的时候,你想确认下服务或是shell是否执行成功。这时候就需要使用wait_for模块。

参数 描述
connect_timeout 在下一个事情发生前等待连接的时间
delay 延时
host 执行模块的host
path 当一个文件存在时,继续下一步
port 监测端口
state started 当对象是端口的时候确保端口是打开的;对象是文件时,确认文件是否存在
stopped 对象是端口的时候确保端口是关闭的;
present 对象是文件的时候确保文件是存在的;
absent 对象是文件的时候确保文件是不存在的

检查某个节点端口是否正常访问

- name: check nginx port for yum repo
wait_for:
port: "{{ yum_port }}"
host: "{{ deploy_node_address }}"
state: started
timeout: 10
run_once: yes

yum模块

参数 描述
enablerepo 激活yum源
name 要操作软件包的名字,也可以传递一个url和本地路径
state 定义软件包的状态(present:安装、absent:删除、latest:安装最新的)

安装apache服务

- name: install apache
yum:
name: httpd
state: present

ansible filter

当涉及到 Ansible 的 Filter 时,有一些内置 Filter 是很常用的。下面是一些常见的 Filter:

Filter 名称 作用
abs 返回一个数字的绝对值
basename 返回一个路径的最后一部分
bool 返回一个布尔值
default 如果变量未定义或为空,则返回一个默认值
difference 返回两个列表之间的差异
filesizeformat 格式化字节大小,如 1MB
first 返回列表的第一个元素
from_json 将 JSON 字符串转换为 Python 对象
from_yaml 将 YAML 字符串转换为 Python 对象
join 将列表中的元素连接为一个字符串
last 返回列表的最后一个元素
length 返回列表、字典或字符串的长度
lower 将字符串转换为小写
max 返回列表中的最大值
min 返回列表中的最小值
random 返回列表中的随机元素
reject 返回列表中不满足指定条件的元素
replace 将字符串中的一个子串替换为另一个子串
select 返回列表中满足指定条件的元素
sort 对列表进行排序
sum 返回列表中所有数字的和
to_json 将 Python 对象转换为 JSON 字符串
to_yaml 将 Python 对象转换为 YAML 字符串
trim 移除字符串开头和结尾的空白字符
union 返回两个列表的并集
unique 返回一个列表中的唯一元素
upper 将字符串转换为大写
urlencode 对字符串进行 URL 编码
version 将版本号字符串转换为可比较的形式

将字符串开头和结尾的空格去除

- name: debug k8s cluster system id
debug:
msg: "k8s cluster System Id is: {{ System_Id.stdout|trim }}"

替换字符串,将192.168.1.1替换为192-168-1-1

- name: get kube etcd pem for prometheus
command: cat /etc/kubernetes/ssl/kube-etcd-{{ hostvars[inventory_hostname]['ansible_' + api_interface]['ipv4']['address'] | regex_replace('\.', '-') }}.pem
register: kube_etcd_pem
when: inventory_hostname in groups['cp_control'][0]

ansible判断

判断类型 描述
when 在任务运行之前用于评估是否需要运行任务
assert 如果表达式不为真,则任务失败
failed_when 当一个任务的返回码符合给定的条件时,将标记任务失败
changed_when 如果命令的执行返回值符合给定的条件,则将结果标记为已更改

when

when条件判断:只条满足when的条件时才执行对应的tasks

---
- hosts: master
tasks:
- name: test host IP address
debug: 'msg="{{ ansible_default_ipv4.address }}"'
when: ansible_default_ipv4.address == "192.168.1.11"

判断chrony配置文件是否存在,如果存在则跳过;如果不存在则复制配置文件

- name: chrony check is exits
stat: path=/etc/chrony.conf.bak
register: chrony_conf_status
#先用register获取chrony.conf.bak文件的状态
- name: backup chrony conf
copy: src=/etc/chrony.conf dest=/etc/chrony.conf.bak
when: chrony_conf_status.stat.exists == False
#判断配置文件是否存在如果存在则不执行该task

定义变量判断:

cloudkitty_hashmaps: "{{ cloudkitty_hashmaps_cp if deloy_cp_region is defined and deploy_cp_region|bool  else cloudkitty_hashmaps_os }}

判断regsiter变量的值,如果两个节点及以上register变量相等,则执行task

- name: mariadb galera cluster first startup
shell: galera_new_cluster >>/dev/null
ignore_errors: yes
when: {{ safe_to_bootstrap.stdout }}|int >=1

判断变量cattle_system_ns_state的结果如果为failed则执行create ns cattle-system任务

- name: check cattle-system namespace is exists
shell: kubectl get ns|grep cattle-system
register: cattle_system_ns_state
ignore_errors: True
run_once: True

- name: create namespace cattle-system
shell: kubectl create namespace cattle-system
when: cattle_system_ns_state | failed
run_once: True

changed_when

先执行task,并对task返回的值进行判断,当满足changed_when指定的条件时说明是执行成功的

---
- hosts: master
tasks:
- name: check hostname
shell: "hostname"
changed_when: ansible_hostname == "master01"

ansible循环

在Ansible中,循环通常使用loop关键字实现。Ansible支持多种类型的循环,包括:

循环类型 描述
loop 基本循环,用于遍历列表、字典等
until 直到某些条件满足之前循环执行
while 在某些条件满足的情况下循环执行
with_* 与变量一起使用的特殊循环,例如with_itemswith_dictwith_file

另外,Ansible还支持嵌套循环和循环控制语句(如breakcontinue等),可以根据具体情况选择使用。

ansible变量

类型 描述
字符串 由单引号、双引号或反斜杠括起来的字符序列,可以包含变量或表达式
数字 整数或浮点数
布尔值 True 或 False
列表 由方括号括起来的元素列表,元素可以是任何类型的值,用逗号分隔
字典 由大括号括起来的键值对,用冒号分隔,键和值之间用等号或空格分隔,键值对之间用逗号分隔
None 表示空值或未定义值的特殊类型

Playbooks

Playboos:简单说就是定义一个配置文件,文件中写入你需要安装的服务,配置文件,变量等信息。可以安装事先定义好的机制完成一个任务

yml脚本语法

  • 文件开头用---开始
  • 在冒号之后,必须存在一个空格
  • name和模块名称必须对齐
  • hosts和tasks必须对齐
  • 在书写key和value的时候,不能存在空格

playbooks组成部分

目录名称 作用
tasks 包含当前角色的所有任务
handlers 包含当前角色的所有处理程序
templates 包含当前角色需要使用的模板文件
files 包含当前角色需要使用的一些文件,这些文件通常是不需要经过模板处理的,如一些二进制文件等
vars 包含当前角色的变量定义文件
defaults 包含当前角色的默认变量文件
meta 包含当前角色的依赖信息,如依赖哪些其它角色等
library 包含当前角色需要使用的Ansible模块,这些模块通常是需要自行编写的
module_utils 包含当前角色需要使用的Ansible模块工具库
lookup_plugins 包含当前角色需要使用的Ansible查找插件
filter_plugins 包含当前角色需要使用的Ansible过滤器插件
test 包含当前角色需要使用的Ansible测试模块
role_name.yml 包含当前角色的主任务文件,可以是多个yml文件,用来定义角色执行时的流程控制

ansible模块开发

检查TCP端口

#!/usr/bin/python
# -*- coding: utf-8 -*-

from ansible.module_utils.basic import AnsibleModule
import socket
import logging

def main():
module = AnsibleModule(
argument_spec=dict(
host=dict(type='str', required=True),
port=dict(type='int', required=True),
timeout=dict(type='int', default=1),
),
supports_check_mode=False,
no_log=True
)

host = module.params['host']
port = module.params['port']
timeout = module.params['timeout']

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(timeout)
result = {}
try:
sock.connect((host, port))
result['msg'] = "Port {} is open on host {}".format(port, host)
result['rc'] = 0
result['status'] = 'ok'
except socket.error as e:
result['msg'] = "Port {} is not open on host {}: ".format(port, host)
result['rc'] = 0
result['status'] = 'failed'
finally:
sock.close()

module.exit_json(**result)


if __name__ == '__main__':
main()

调用第三方接口处理数据

import requests
import hashlib
import logging
from ansible.module_utils.basic import AnsibleModule

logging.basicConfig(level=logging.DEBUG,format="%(asctime)s %(levelname)s %(message)s")

class API:
pass

def main():
module = AnsibleModule(
argument_spec=dict(
host=dict(type='str', required=True),
login_user=dict(type='str', required=True),
login_pass=dict(type='str', required=True),
name=dict(type='str', required=True)
),
supports_check_mode=False,
no_log=True
)
host = module.params['host']
login_user = module.params['login_user']
login_pass = module.params['login_pass']
name = module.params['name']
api = API(host, login_user, login_pass)
data = api.get_conf(name)
result = {}
result['stdout'] = data
module.exit_json(**result)


if __name__ == '__main__':
main()

案例

生成随机数

- name: Generate Random seed
set_fact:
seed: "{{ ansible_nodename }}-{{ ansible_host }}"

- name: Generate GID NUM
set_fact:
gid_num: "{{ range(100) | random(seed=seed) }}"

- name: Format GID
set_fact:
gid: "{{ 10000 + '{:04d}'.format(gid_num|int)|int }}"

- name: Generate Random GID
debug:
msg: "gid: {{ gid }}"

在配置文件中循环生成主机组ip

{% for host in groups['all']%} {{ hostvars[host]['ansible' + hostvars[host]['api_interface']]['ipv4']['address'] }}:2181{% if not loop.last %},{% endif %}{% endfor %}

获取节点IP地址

{{ hostvars[inventory_hostname]['ansible_' + hostvars[inventory_hostname]['api_interface']['ipv4']['address']] }}
文章作者: 慕容峻才
文章链接: https://www.acaiblog.top/ansible教程/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 阿才的博客
微信打赏
支付宝打赏