当前位置 : 主页 > 操作系统 > centos >

34-Ansible常用playbook和大型项目role角色拆分

来源:互联网 收集:自由互联 发布时间:2022-12-23
yaml简单示例 #格式要求 在单一文件第一行,用连续三个连字号"-" 开始,还有选择性的连续三个点号( ... )用来表示文件的结尾 次行开始正常写Playbook的内容,一般建议写明该Playbook的功

yaml简单示例

#格式要求 在单一文件第一行,用连续三个连字号"-" 开始,还有选择性的连续三个点号( ... )用来表示文件的结尾 次行开始正常写Playbook的内容,一般建议写明该Playbook的功能 使用#号注释代码 缩进的级别也必须是一致的,同样的缩进代表同样的级别,程序判别配置的级别是通过缩进结合换 行来实现的 缩进不支持tab,必须使用空格进行缩进 缩进的空格数不重要,只要相同层级的元素左对齐即可 YAML文件内容是区别大小写的,key/value的值均需大小写敏感 多个key/value可同行写也可换行写,同行使用,分隔 key后面冒号要加一个空格 比如: key: value value可是个字符串,也可是另一个列表 YAML文件扩展名通常为yml或yaml案例:palybook 配置nginx服务到被控制端[root@ubuntu2204 ~]#cat test.yaml ---#This is a test yaml-hosts: webservers tasks: - name: install package apt: name=nginx - name: config copy: src=/data/files/nginx.conf dest=/etc/nginx/nginx.conf notify: restart service - name: sub config copy: src: /data/files/www.mooreyxia.conf dest: /etc/nginx/conf.d/www.mooreyxia.conf notify: restart service - name: create data file file: path: /data/mooreyxiasite state: directory - name: html page file copy: src: /data/files/index.html dest: /data/mooreyxiasite - name: create group group: name=www gid=88 system=yes - name: create user user: name=www group=www system=yes shell=/sbin/nologin - name: start service service: name: nginx state: started enabled: yes handlers: - name: restart service service: name: nginx state: restarted

Playbook调用

[root@ubuntu2204 ~]#ansible-playbook --helpusage: ansible-playbook [-h] [--version] [-v] [-k] [--private-key PRIVATE_KEY_FILE] [-u REMOTE_USER] [-c CONNECTION] [-T TIMEOUT] [--ssh-common-args SSH_COMMON_ARGS] [--sftp-extra-args SFTP_EXTRA_ARGS] [--scp-extra-args SCP_EXTRA_ARGS] [--ssh-extra-args SSH_EXTRA_ARGS] [--force-handlers] [--flush-cache] [-b] [--become-method BECOME_METHOD] [--become-user BECOME_USER] [-K] [-t TAGS] [--skip-tags SKIP_TAGS] [-C] [--syntax-check] [-D] [-i INVENTORY] [--list-hosts] [-l SUBSET] [-e EXTRA_VARS] [--vault-id VAULT_IDS] [--ask-vault-password | --vault-password-file VAULT_PASSWORD_FILES] [-f FORKS] [-M MODULE_PATH] [--list-tasks] [--list-tags] [--step] [--start-at-task START_AT_TASK] playbook [playbook ...]Runs Ansible playbooks, executing the defined tasks on the targeted hosts.positional arguments: playbook Playbook(s)options: --ask-vault-password, --ask-vault-pass ask for vault password --flush-cache clear the fact cache for every host in inventory --force-handlers run handlers even if a task fails --list-hosts outputs a list of matching hosts; does not execute anything else --list-tags list all available tags --list-tasks list all tasks that would be executed --skip-tags SKIP_TAGS only run plays and tasks whose tags do not match these values --start-at-task START_AT_TASK start the playbook at the task matching this name --step one-step-at-a-time: confirm each task before running --syntax-check perform a syntax check on the playbook, but do not execute it --vault-id VAULT_IDS the vault identity to use --vault-password-file VAULT_PASSWORD_FILES, --vault-pass-file VAULT_PASSWORD_FILES vault password file --version show program's version number, config file location, configured module search path, module location, executable location and exit -C, --check don't make any changes; instead, try to predict some of the changes that may occur -D, --diff when changing (small) files and templates, show the differences in those files; works great with --check -M MODULE_PATH, --module-path MODULE_PATH prepend colon-separated path(s) to module library (default=~/.ansible/plugins/modules:/usr/share/ansible/plugins/modules) -e EXTRA_VARS, --extra-vars EXTRA_VARS set additional variables as key=value or YAML/JSON, if filename prepend with @ -f FORKS, --forks FORKS specify number of parallel processes to use (default=5) -h, --help show this help message and exit -i INVENTORY, --inventory INVENTORY, --inventory-file INVENTORY specify inventory host path or comma separated host list. --inventory-file is deprecated -l SUBSET, --limit SUBSET further limit selected hosts to an additional pattern -t TAGS, --tags TAGS only run plays and tasks tagged with these values -v, --verbose verbose mode (-vvv for more, -vvvv to enable connection debugging)Connection Options: control as whom and how to connect to hosts --private-key PRIVATE_KEY_FILE, --key-file PRIVATE_KEY_FILE use this file to authenticate the connection --scp-extra-args SCP_EXTRA_ARGS specify extra arguments to pass to scp only (e.g. -l) --sftp-extra-args SFTP_EXTRA_ARGS specify extra arguments to pass to sftp only (e.g. -f, -l) --ssh-common-args SSH_COMMON_ARGS specify common arguments to pass to sftp/scp/ssh (e.g. ProxyCommand) --ssh-extra-args SSH_EXTRA_ARGS specify extra arguments to pass to ssh only (e.g. -R) -T TIMEOUT, --timeout TIMEOUT override the connection timeout in seconds (default=10) -c CONNECTION, --connection CONNECTION connection type to use (default=smart) -k, --ask-pass ask for connection password -u REMOTE_USER, --user REMOTE_USER connect as this user (default=None)Privilege Escalation Options: control how and which user you become as on target hosts --become-method BECOME_METHOD privilege escalation method to use (default=sudo), use `ansible-doc -t become -l` to list valid choices. --become-user BECOME_USER run operations as this user (default=root) -K, --ask-become-pass ask for privilege escalation password -b, --become run operations with become (does not imply password prompting)

Playbook核心组件

一个playbook 中由多个组件组成,其中所用到的常见组件类型如下:

  • Hosts 执行的远程主机列表
  • Tasks 任务集,由多个task的元素组成的列表实现,每个task是一个字典,一个完整的代码块功能需最少元素需包括 name 和 task,一个name只能包括一个task
  • Variables 内置变量或自定义变量在playbook中调用
  • Templates 模板,可替换模板文件中的变量并实现一些简单逻辑的文件
  • Handlers 和 notify 结合使用,由特定条件触发的操作,满足条件方才执行,否则不执行
  • tags 标签 指定某条任务执行,用于选择运行playbook中的部分代码。ansible具有幂等性,因此会自动跳过没有变化的部分,即便如此,有些代码为测试其确实没有发生变化的时间依然会非常地长。此时,如果确信其没有变化,就可以通过tags跳过此些代码片断

hosts 组件

Hosts:playbook中的每一个play的目的都是为了让特定主机以某个指定的用户身份执行任务。hosts用于指定要执行指定任务的主机,须事先定义在主机清单中

one.example.comone.example.com:two.example.com192.168.1.50192.168.1.*webservers:dbservers #或者,两个组的并集webservers:&dbservers #与,两个组的交集webservers:!dbservers #在webservers组,但不在dbservers组案例:- hosts: webservers:appservers

remote_user 组件

remote_user: 可用于Host和task中。也可以通过指定其通过sudo的方式在远程主机上执行任务,其可用于play全局或某任务;此外,甚至可以在sudo时使用sudo_user指定sudo时切换的用户

案例:- hosts: webservers remote_user: root tasks: - name: test connection ping: remote_user: moore sudo: yes #默认sudo为root sudo_user:mooreyxia #sudo为mooreyxia

task列表和action组件

  • play的主体部分是task list,task list中有一个或多个task,各个task 按次序逐个在hosts中指定的所有主机上执行,即在所有主机上完成第一个task后,再开始第二个task
  • task的目的是使用指定的参数执行模块,而在模块参数中可以使用变量。模块执行是幂等的,这意味着多次执行是安全的,因为其结果均一致
  • 每个task都应该有其name,用于playbook的执行结果输出,建议其内容能清晰地描述任务执行步骤。
  • 如果未提供name,则action的结果将用于输出
task两种格式:action: module arguments #示例: action: shell wall hellomodule: arguments #建议使用 #示例: shell: wall hello注意:shell和command模块后面跟命令,而非key=value案例:[root@ansible ansible]#cat hello.yml---#first yaml文件#- hosts: webservers remote_user: root gather_facts: no tasks: - name: task1 debug: msg="task1 running" - name: task2 debug: msg="task2 running" - hosts: appservers remote_user: root gather_facts: no tasks: - name: task3 debug: msg="task3 running" - name: task4 debug: msg="task4 running"

其它组件说明 tags notify

  • 某任务的状态在运行后为changed时,可通过"notify"通知给相应的handlers任务
  • 还可以通过"tags"给task 打标签,可在ansible-playbook命令上使用-t指定进行调用
ShellScripts VS Playbook 案例#SHELL脚本实现#!/bin/bash# 安装Apacheyum install --quiet -y httpd# 复制配置文件cp /tmp/httpd.conf /etc/httpd/conf/httpd.confcp/tmp/vhosts.conf /etc/httpd/conf.d/# 启动Apache,并设置开机启动systemctl enable --now httpd#Playbook实现---- hosts: webservers remote_user: root gather_facts: no tasks: - name: "安装Apache" yum: name=httpd - name: "复制配置文件" copy: src=/tmp/httpd.conf dest=/etc/httpd/conf/ notify: restart service tags: config - name: "复制配置文件" copy: src=/tmp/vhosts.conf dest=/etc/httpd/conf.d/ notify: restart service tags: config - name: "启动Apache,并设置开机启动" service: name=httpd state=started enabled=yes handlers: - name: restart service service: httpd state: restarted #调用格式:ansible-playbook <filename.yml> ... [options]ansible-playbook install-apache.yaml或者只执行tag部分ansible-playbook -t config install-apache.yaml

force_handlers

如果不论前面的task成功与否,都希望handlers能执行, 可以使用force_handlers: yes 强制执行handler

案例: 强制调用handlers- hosts: webservers force_handlers: yes #无论task中的任何一个task失败,仍强制调用handlers tasks: - name: config file copy: src=nginx.conf dest=/etc/nginx/nginx.conf notify: restart nginx - name: install package yum: name=no_exist_package handlers: - name: restart nginx service: name=nginx state=restarted

Playbook中使用tags组件

在playbook文件中,可以利用tags组件,为特定 task 指定标签,当在执行playbook时,可以只执行特定tags的task,而非整个playbook文件

  • 可以一个task对应多个tag,也可以多个task对应同一个tag
  • 还有另外3个特殊关键字用于标签, tagged, untagged 和 all,它们分别是仅运行已标记,只有未标记和所有任务
  • tags 主要用于调试环境
范例: tag 标签vim httpd.yml---# tags example- hosts: webservers remote_user: root gather_facts: no tasks: - name: Install httpd yum: name=httpd state=present - name: Install configure file copy: src=files/httpd.conf dest=/etc/httpd/conf/ tags: [ conf,file ] #写在一行 - conf #写成多行 - file - name: start httpd service tags: service service: name=httpd state=started enabled=yes #列出标签[root@ansible ~]#ansible-playbook --list-tags httpd.yml#执行有指定标签的任务[root@ansible ~]#ansible-playbook -t conf,service httpd.yml#忽略执行指定标签的task[root@ansible ~]#ansible-playbook --skip-tags conf httpd.yml#忽略执行没有标签的任务,即只执行有标签的任务[root@ansible ~]#ansible-playbook httpd.yml --skip-tags untagged

Playbook中使用变量

变量定义:variable=valuevariable: value变量调用方式:通过{{ variable_name }} 调用变量,且变量名前后建议加空格,有时用"{{ variable_name }}"才生效变量来源:1. ansible 的 setup facts 远程主机的所有变量都可直接调用2. 通过命令行指定变量,优先级最高 ansible-playbook -e varname=value test.yml3. 在playbook文件中定义 vars: var1: value1 var2: value24. 在独立的变量YAML文件中定义- hosts: all vars_files: - vars.yml5. 在主机清单文件中定义主机(普通)变量:主机组中主机单独定义,优先级高于公共变量组(公共)变量:针对主机组中所有主机定义统一变量6. 在项目中针对主机和主机组定义在项目目录中创建 host_vars和group_vars目录7. 在role中定义变量的优先级从高到低如下-e 选项定义变量 -->playbook中vars_files --> playbook中vars变量定义 -->host_vars/主机名文件 -->主机清单中主机变量--> group_vars/主机组名文件-->group_vars/all文件--> 主机清单组变量

使用 setup 模块中变量

#使用 facts 变量facts 包括的信息很多,如: 主机名,IP,CPU,内存,网卡等facts 变量的实际使用场景案例通过facts变量获取被控端CPU的个数信息,从而生成不同的Nginx配置文件通过facts变量获取被控端内存大小信息,从而生成不同的memcached的配置文件通过facts变量获取被控端主机名称信息,从而生成不同的Zabbix配置文件通过facts变量获取被控端网卡信息,从而生成不同的主机名......案例:使用setup变量[root@ubuntu2204 ~]#ansible localhost -m setup -a 'filter="ansible_default_ipv4"'localhost | SUCCESS => { "ansible_facts": { "ansible_default_ipv4": { "address": "10.0.0.200", "alias": "eth0", "broadcast": "10.0.0.255", "gateway": "10.0.0.2", "interface": "eth0", "macaddress": "00:0c:29:df:99:92", "mtu": 1500, "netmask": "255.255.255.0", "network": "10.0.0.0", "type": "ether" } }, "changed": false}

性能优化

每次执行playbook,默认会收集每个主机的所有facts变量,将会导致速度很慢,可以采用下面方法加速

方法1 - 关闭facts采集加速执行,此方法将导致无法使用facts变量- hosts: all gather_facts: no方法2 - 设置facts 的缓存,将facts变量信息存在redis服务器中[root@ansible ~]# cat /etc/ansible/ansible.cfg[defaults]# smart 表示默认收集 facts,但 facts 已有的情况下不会收集,即使用缓存 facts# implicit 表示默认收集 facts,要禁止收集,必须使用 gather_facts: False# explicit 则表示默认不收集,要显式收集,必须使用gather_facts: Truegathering = smart #在使用 facts 缓存时设置为smartfact_caching_timeout = 86400 #缓存时长fact_caching = redis #缓存存在redis中fact_caching_connection = 10.0.0.100:6379:0 #0表示redis的0号数据库#若redis设置了密码fact_caching_connection = 10.0.0.100:6379:0:password

register 注册变量 - 使用register将捕获命令的输出保存在临时变量中

案例: 利用debug 模块输出变量[root@ubuntu2204 ~]#cat register1.yaml ---#register 模块测试- hosts: webservers tasks: - name: get variable shell: hostname register: name1 - name: "print variable" debug: msg: "{{ name1 }}"[root@ubuntu2204 ~]#ansible-playbook register1.yaml PLAY [webservers] *****************************************************************************************************************************************************************TASK [Gathering Facts] ************************************************************************************************************************************************************[WARNING]: Platform linux on host 10.0.0.8 is using the discovered Python interpreter at /usr/bin/python3.9, but future installation of another Python interpreter could changethe meaning of that path. See https://docs.ansible.com/ansible/2.10/reference_appendices/interpreter_discovery.html for more information.ok: [10.0.0.8]ok: [10.0.0.200]TASK [get variable] ***************************************************************************************************************************************************************changed: [10.0.0.200]changed: [10.0.0.8]TASK [print variable] *************************************************************************************************************************************************************ok: [10.0.0.8] => { "msg": { "changed": true, "cmd": "hostname", "delta": "0:00:00.003766", "end": "2022-12-21 11:12:26.361378", "failed": false, "rc": 0, "start": "2022-12-21 11:12:26.357612", "stderr": "", "stderr_lines": [], "stdout": "rocky8.mooreyxia.org", "stdout_lines": [ "rocky8.mooreyxia.org" ] }}ok: [10.0.0.200] => { "msg": { "changed": true, "cmd": "hostname", "delta": "0:00:00.029575", "end": "2022-12-21 11:12:26.283027", "failed": false, "rc": 0, "start": "2022-12-21 11:12:26.253452", "stderr": "", "stderr_lines": [], "stdout": "ubuntu2204.mooreyxia.org", "stdout_lines": [ "ubuntu2204.mooreyxia.org" ] }}PLAY RECAP ************************************************************************************************************************************************************************10.0.0.200 : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 10.0.0.8 : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

将多个变量放在一个文件中

[root@ansible ~]#cat varspkname1: memcachedpkname2: vsftpd[root@ansible ~]#vim var2.yml---- hosts: webservers remote_user: root tasks: - name: install package {{ pkname1 } yum: name={{ pkname1 }} state=present - name: install package {{ pkname2 } yum: name={{ pkname2 }} state=present[root@ansible ~]#ansible-playbook -e pkname1=memcached -e pkname2=httpd var2.yml[root@ansible ~]#ansible-playbook -e '@vars' var2.yml

案例: 安装指定版本的MySQL - 格式需要调整

[root@ansible ansible]#cat install_mysql.yml---# install mysql-5.6.46-linux-glibc2.12-x86_64.tar.gz- hosts: dbservers remote_user: root gather_facts: no vars: version: "mysql-5.6.46-linux-glibc2.12-x86_64" suffix: "tar.gz" file: "{{version}}.{{suffix}}" tasks: - name: install packages yum: name=libaio,perl-Data-Dumper,perl-Getopt-Long - name: create mysql group group: name=mysql gid=306 - name: create mysql user user: name=mysql uid=306 group=mysql shell=/sbin/nologin system=yes create_home=no home=/data/mysql - name: copy tar to remote host and file mode unarchive: src=/data/ansible/files/{{file}} dest=/usr/local/ owner=root group=root - name: create linkfile /usr/local/mysql file: src=/usr/local/{{version}} dest=/usr/local/mysql state=link - name: data dir shell: chdir=/usr/local/mysql/ ./scripts/mysql_install_db --datadir=/data/mysql --user=mysql tags: data - name: config my.cnf copy: src=/data/ansible/files/my.cnf dest=/etc/my.cnf - name: service script shell: /bin/cp /usr/local/mysql/support-files/mysql.server /etc/init.d/mysqld - name: enable service shell: /etc/init.d/mysqld start;chkconfig --add mysqld;chkconfig mysqld on tags: service - name: PATH variable copy: content='PATH=/usr/local/mysql/bin:$PATH' dest=/etc/profile.d/mysql.sh - name: secure script script: /data/ansible/files/secure_mysql.sh tags: script

使用专用的公共的变量文件

可以在一个独立的playbook文件中定义公共变量,在其它的playbook文件中可以引用变量文件中的变量,此方式比playbook中定义的变量优化级高

vim vars.yml---# variables filepackage_name: mariadb-serverservice_name: mariadbvim var5.yml---#install package and start service- hosts: dbservers remote_user: root vars_files: - vars.yml tasks: - name: install package yum: name={{ package_name }} tags: install - name: start service service: name={{ service_name }} state=started enabled=yes

所有项目的组(公共)变量

在inventory 主机清单文件中赋予给指定组内所有主机上的在playbook中可用的变量,如果和主机变是同名,优先级低于主机变量

案例1:[root@ansible ~]#vim /etc/ansible/hosts[webservers]10.0.0.8 hname=www1 domain=moore.io10.0.0.7 hname=www2[webservers:vars]mark="-"[all:vars]domain=mooreyxia.org[root@ansible ~]#ansible webservers -m hostname -a 'name={{ hname }}{{ mark }}{{ domain }}'#命令行指定变量:[root@ansible ~]#ansible webservers -e domain=magedu.cn -m hostname -a 'name={{ hname }}{{ mark }}{{ domain }}'案例2:k8s 的ansible 变量文件[kube-master]10.0.0.10110.0.0.10210.0.0.103 NEW_MASTER=yes[etcd]10.0.0.104 NODE_NAME=etcd110.0.0.105 NODE_NAME=etcd210.0.0.106 NODE_NAME=etcd3[kube-node]10.0.0.10710.0.0.10810.0.0.109 NEW_NODE=yes[harbor][ex-lb]10.0.0.111 LB_ROLE=master EX_APISERVER_VIP=10.0.0.100 EX_APISERVER_PORT=844310.0.0.112 LB_ROLE=backup EX_APISERVER_VIP=10.0.0.100 EX_APISERVER_PORT=8443[chrony][all:vars]CONTAINER_RUNTIME="docker"CLUSTER_NETWORK="calico"PROXY_MODE="ipvs"SERVICE_CIDR="192.168.0.0/16"CLUSTER_CIDR="172.16.0.0/16"NODE_PORT_RANGE="20000-60000"CLUSTER_DNS_DOMAIN="magedu.local."bin_dir="/usr/bin"ca_dir="/etc/kubernetes/ssl"base_dir="/etc/ansible"

针对当前项目的主机和主机组的变量

生产建议在每个项目对应的目录中创建额外的两个变量目录,分别是host_vars和group_vars

  • host_vars下面的文件名和主机清单主机名一致,针对单个主机进行变量定义 - 格式:host_vars/hostname
  • group_vars下面的文件名和主机清单中组名一致, 针对单个组进行变量定义 - 格式: group_vars/groupname
  • group_vars/all文件内定义的变量对所有组都有效
案例:特定项目的主机和组变量[root@ubuntu2204 ~]#mkdir -pv /data/ansiblemkdir: 已创建目录 '/data/ansible'[root@ubuntu2204 ~]#cd /data/ansible/[root@ubuntu2204 ansible]#mkdir host_vars[root@ubuntu2204 ansible]#mkdir group_vars[root@ubuntu2204 ansible]#vim host_vars/10.0.0.8[root@ubuntu2204 ansible]#vim host_vars/10.0.0.200[root@ubuntu2204 ansible]#cat host_vars/10.0.0.8id: 2[root@ubuntu2204 ansible]#cat host_vars/10.0.0.200id: 1[root@ubuntu2204 ansible]#vim group_vars/webservers[root@ubuntu2204 ansible]#cat group_vars/webserversname: web[root@ubuntu2204 ansible]#vim group_vars/all[root@ubuntu2204 ansible]#cat group_vars/alldomain: mooreyxia.org[root@ubuntu2204 ansible]#tree host_vars/ group_vars/host_vars/├── 10.0.0.200└── 10.0.0.8group_vars/├── all└── webservers0 directories, 2 files[root@ubuntu2204 ansible]#vim test.yaml[root@ubuntu2204 ansible]#cat test.yaml - hosts: webservers tasks: - name: get variable command: echo "{{ name }}{{ id }}.{{ domain }}" register: result - name: print variable debug: msg: "{{ result.stdout }}"#执行结果[root@ubuntu2204 ansible]#ansible-playbook test.yaml PLAY [webservers] *****************************************************************************************************************************************************************TASK [Gathering Facts] ************************************************************************************************************************************************************[WARNING]: Platform linux on host 10.0.0.8 is using the discovered Python interpreter at /usr/bin/python3.9, but future installation of another Python interpreter could changethe meaning of that path. See https://docs.ansible.com/ansible/2.10/reference_appendices/interpreter_discovery.html for more information.ok: [10.0.0.8]ok: [10.0.0.200]TASK [get variable] ***************************************************************************************************************************************************************changed: [10.0.0.200]changed: [10.0.0.8]TASK [print variable] *************************************************************************************************************************************************************ok: [10.0.0.8] => { "msg": "web2.mooreyxia.org"}ok: [10.0.0.200] => { "msg": "web1.mooreyxia.org"}PLAY RECAP ************************************************************************************************************************************************************************10.0.0.200 : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 10.0.0.8 : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

Template 模板

模板是一个文本文件,可以用于根据每个主机的不同环境而为生成不同的文件

template功能:可以根据和参考模块文件,动态生成相类似的配置文件

template文件存建议放于templates目录下,且命名为 .j2 结尾

yaml/yml 文件和templates目录平级,此时playbook中指定模板文件时可不用指定路径

案例:利用template 同步nginx配置文件#准备templates/nginx.conf.j2文件[root@ubuntu2204 ansible]#cat templates/nginx.conf.j2 user {{user}};worker_processes {{ansible_processor_vcpus*2}};#error_log logs/error.log;#error_log logs/error.log notice;#error_log logs/error.log info;#pid logs/nginx.pid;events { worker_connections {{connection}};}http { include mime.types; default_type application/octet-stream;...#准备playbook[root@ubuntu2204 ansible]#cat templates1.yaml ---- hosts: webservers vars: nginx_ver: 1.22.1 nginx_file: "nginx-{{nginx_ver}}.tar.gz" nginx_url: "http://nginx.org/download/{{nginx_file}}" user: www connection: "2048" install_path: /tmp/nginx tasks: - name: download nginx src file unarchive: src: "{{nginx_url}}" dest: /tmp/ remote_src: yes - name: create install path file: path: "{{install_path}}" state: directory - name: create nginx config template: src: nginx.conf.j2 dest: "{{install_path}}/nginx.conf" mode: 600 owner: bin group: daemon#执行[root@ubuntu2204 ansible]#ansible-playbook templates1.yaml [WARNING]: Found variable using reserved name: connectionPLAY [webservers] **********************************************************************************************TASK [Gathering Facts] *****************************************************************************************[WARNING]: Platform linux on host 10.0.0.8 is using the discovered Python interpreter at /usr/bin/python3.9,but future installation of another Python interpreter could change the meaning of that path. Seehttps://docs.ansible.com/ansible/2.10/reference_appendices/interpreter_discovery.html for more information.ok: [10.0.0.8]ok: [10.0.0.200]TASK [download nginx src file] *********************************************************************************changed: [10.0.0.8]changed: [10.0.0.200]TASK [create install path] *************************************************************************************changed: [10.0.0.200]changed: [10.0.0.8]TASK [create nginx config] *************************************************************************************changed: [10.0.0.200]changed: [10.0.0.8]PLAY RECAP *****************************************************************************************************10.0.0.200 : ok=4 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 10.0.0.8 : ok=4 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 #查看10.0.0.8[root@rocky8 ~]#ll /tmp/total 0[root@rocky8 ~]#ll /tmp/total 0drwxr-xr-x 2 root root 24 Dec 21 17:38 nginxdrwxr-xr-x 8 moore moore 158 Oct 19 16:02 nginx-1.22.1[root@rocky8 ~]#cat /tmp/nginx/nginx.conf user www;worker_processes 4;#error_log logs/error.log;#error_log logs/error.log notice;#error_log logs/error.log info;#pid logs/nginx.pid;events { worker_connections 2048;}http { include mime.types; default_type application/octet-stream; #log_format main '$remote_addr - $remote_user [$time_local] "$request" ' # '$status $body_bytes_sent "$http_referer" ' # '"$http_user_agent" "$http_x_forwarded_for"'; #access_log logs/access.log main; sendfile on; #tcp_nopush on; #keepalive_timeout 0; keepalive_timeout 65;....10.0.0.200 也一样

template中也可以使用流程控制 for 循环和 if 条件判断,实现动态生成文件功能

案例:for 循环#准备templates[root@ubuntu2204 ~]#cat /data/ansible/templates/web.conf.j2 {% for vhost in vhosts %}server {listen {{ vhost.listen }}server_name {{ vhost.server_name }}root {{ vhost.root }}}{% endfor %}#准备palybook 下载 创建存放文件 配置文件[root@ubuntu2204 ~]#cat /data/ansible/templates.yaml ---- hosts: webservers vars: nginx_ver: 1.22.1 nginx_file: "nginx-{{nginx_ver}}.tar.gz" nginx_url: "http://nginx.org/download/{{nginx_file}}" user: www connection: "2048" install_path: /tmp/nginx vhosts: - listen: 81 server_name: www.a.cn root: web1 - listen: 82 server_name: www.b.com root: web2 - listen: 83 server_name: www.c.org root: web3 tasks: - name: download nginx src file unarchive: src: "{{nginx_url}}" dest: /tmp/ remote_src: yes - name: create install path file: path: "{{install_path}}" state: directory - name: create nginx config template: src: nginx.conf.j2 dest: "{{install_path}}/nginx.conf" mode: 600 owner: bin group: daemon#执行[root@ubuntu2204 ansible]#ansible-playbook templates.yaml [WARNING]: Found variable using reserved name: connectionPLAY [webservers] **********************************************************************************************TASK [Gathering Facts] *****************************************************************************************[WARNING]: Platform linux on host 10.0.0.8 is using the discovered Python interpreter at /usr/bin/python3.9,but future installation of another Python interpreter could change the meaning of that path. Seehttps://docs.ansible.com/ansible/2.10/reference_appendices/interpreter_discovery.html for more information.ok: [10.0.0.8]ok: [10.0.0.200]TASK [download nginx src file] *********************************************************************************changed: [10.0.0.200]changed: [10.0.0.8]TASK [create install path] *************************************************************************************changed: [10.0.0.200]changed: [10.0.0.8]TASK [create nginx config] *************************************************************************************changed: [10.0.0.200]changed: [10.0.0.8]PLAY RECAP *****************************************************************************************************10.0.0.200 : ok=4 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 10.0.0.8 : ok=4 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 #查看结果10.0.0.200[root@ubuntu2204 ansible]#ll /tmp/nginxnginx/ nginx-1.22.1/ [root@ubuntu2204 ansible]#cat /tmp/nginx/nginx.conf server {listen 81server_name www.a.cnroot web1}server {listen 82server_name www.b.comroot web2}server {listen 83server_name www.c.orgroot web3}10.0.0.8[root@rocky8 ~]#ll /tmp/total 0drwxr-xr-x 2 root root 24 Dec 21 17:24 nginxdrwxr-xr-x 8 moore moore 158 Oct 19 16:02 nginx-1.22.1[root@rocky8 ~]#cat /tmp/nginx/nginx.conf server {listen 81server_name www.a.cnroot web1}server {listen 82server_name www.b.comroot web2}server {listen 83server_name www.c.orgroot web3}案例:if 条件判断#templnginx6.yml- hosts: webservers remote_user: root vars: nginx_vhosts: - web1: listen: 8080 root: "/var/www/nginx/web1/" - web2: listen: 8080 server_name: "web2.mooreyxia.org" root: "/var/www/nginx/web2/" - web3: listen: 8080 server_name: "web3.mooreyxia.org" root: "/var/www/nginx/web3/" tasks: - name: template config to template: src=nginx.conf5.j2 dest=/data/nginx5.conf #templates/nginx.conf6.j2{% for vhost in nginx_vhosts %}server {listen {{ vhost.listen }}{% if vhost.server_name is defined %}server_name {{ vhost.server_name }} #注意缩进{% endif %}root {{ vhost.root }} #注意缩进}{% endfor %}#生成的结果server { listen 8080 root /var/www/nginx/web1/}server { listen 8080 server_name web2.mooreyxia.org root /var/www/nginx/web2/}server { listen 8080 server_name web3.mooreyxia.org root /var/www/nginx/web3/}

使用循环迭代

案例1:在task中使用with_items给定要迭代的元素列表---- hosts: webservers remote_user: root tasks: - name: add several users user: name={{ item }} state=present groups=wheel with_items: - testuser1 - testuser2 - testuser3#上面语句的功能等同于下面的语句 - name: add several users user: name=testuser1 state=present groups=wheel - name: add several users user: name=testuser2 state=present groups=wheel - name: add several users user: name=testuser3 state=present groups=wheel案例2:迭代嵌套子变量---- hosts: webservers remote_user: root tasks: - name: add some groups group: name={{ item }} state=present with_items: - nginx - mysql - apache - name: add some users user: name={{ item.user }} group={{ item.group }} uid={{item.uid}} state=present with_items: - { user: 'nginx', group: 'nginx',uid: "80" } - { user: 'mysql', group: 'mysql' ,uid: "3306"} - { user: 'apache', group: 'apache',uid: "8080"}

条件判断 when

when语句可以实现条件测试。如果需要根据变量、facts或此前任务的执行结果来做为某task执行与否的前提时要用到条件测试,通过在task后添加when子句即可使用jinja2的语法格式条件测试

案例:判断OS版本[root@ansible ansible]#cat when.yml- hosts: all tasks: - name: install httpd yum: name: "httpd" when: - ansible_distribution_file_variety == "RedHat" - name: install package apt: name: "apache2" when: - ansible_distribution_file_variety == "Debian"

分组 block

当想在满足同样条件下,执行多个任务时,就需要分组。而不再针对每个任务都是用 when

[root@ansible ansible]#cat block.yml---- hosts: localhost tasks: - block: - debug: msg="first" - debug: msg="second" when: - ansible_facts['distribution'] == "CentOS" - ansible_facts['distribution_major_version'] == "8"#相当于下面写法---- hosts: localhost tasks: - debug: msg="first" when: - ansible_facts['distribution'] == "CentOS" - ansible_facts['distribution_major_version'] == "8" - debug: msg="second" when: - ansible_facts['distribution'] == "CentOS" - ansible_facts['distribution_major_version'] == "8"

changed_when

关闭 changed 状态 - 当确定某个task不会对被控制端做修改时但执行结果却显示是黄色的changed状态,可以通过 changed_when: false 关闭changed状态

案例:changed_when 检查task返回结果,决定是否继续向下执行[root@ansible ansible]#cat test_changed_when.yml---- hosts: webservers tasks: - name: install nginx yum: name=nginx - name: config file template: src="nginx.conf.j2" dest="/etc/nginx/nginx.conf" notify: restart nginx - name: check config shell: /usr/sbin/nginx -t register: check_nginx_config changed_when: - check_nginx_config.stdout.find('successful') #如果执行结果中有successful字符串,则继续执行,如果没有则停止向下执行 - false #nginx -t 每次成功执行是changed状态,关闭此changed状态 - name: start service service: name=nginx state=started enabled=yes handlers: - name: restart nginx service: name=nginx state=restarted

滚动执行

管理节点过多导致的超时问题解决方法

默认情况下,Ansible将尝试并行管理playbook中所有的机器。对于滚动更新用例,可以使用serial关键字定义Ansible一次应管理多少主机,还可以将serial关键字指定为百分比,表示每次并行执行的主机数占总数的比例

案例:#vim test_serial.yml---- hosts: all serial: 2 #每次只同时处理2个主机,将所有task执行完成后,再选下2个主机再执行所有task,直至所有主机 gather_facts: False tasks: - name: task one comand: hostname - name: task two command: hostname

委派至其它主机执行

利用委托技术,可以在非当前被控主机的其它主机上执行指定操作

注意: 当前执行的被管理端主机需要实现到被委派主机的ssh key 验证才能实现委派

案例: 创建普通用户基于ssh key验证[root@ansible ansible]#cat ssh_key_push.yml---# 创建普通用户管理ansible- hosts: webservers vars: - user_name: ssh_demo tasks: # manage 节点执行 - name: Create Manager {{ user_name }} user: name: "{{ user_name }}" generate_ssh_key: yes ssh_key_bits: 2048 ssh_key_file: ".ssh/id_rsa" register: user_message delegate_to: localhost # 委派给管理端 run_once: true # 委派任务仅执行一次 # node 节点执行 - name: 打印管理用户的key结果 debug: msg: "{{ user_message.ssh_public_key }}" - name: 在被控端上创建用户 user: name: "{{ user_name }}" - name: 在被控端上创建用户.ssh目录 file: path: "/home/{{ user_name }}/.ssh" state: directory owner: "{{ user_name }}" group: "{{ user_name }}" mode: "0700" - name: 将管理端 {{ user_name }} 用户的key存储到被控端 copy: content: "{{ user_message.ssh_public_key }}" dest: "/home/{{ user_name }}/.ssh/authorized_keys" owner: "{{ user_name }}" group: "{{ user_name }}" mode: "0600" - name: 配置被控制端sudo提权 lineinfile: path: /etc/sudoers line: "{{ user_name }} ALL=(ALL) NOPASSWD:ALL" #执行[root@ubuntu2204 ansible]#ansible-playbook ssh_key_push.yaml PLAY [webservers] **********************************************************************************************TASK [Gathering Facts] *****************************************************************************************[WARNING]: Platform linux on host 10.0.0.8 is using the discovered Python interpreter at /usr/bin/python3.9,but future installation of another Python interpreter could change the meaning of that path. Seehttps://docs.ansible.com/ansible/2.10/reference_appendices/interpreter_discovery.html for more information.ok: [10.0.0.8]ok: [10.0.0.200]TASK [Create Manager ssh_demo] *********************************************************************************changed: [10.0.0.8]TASK [打印管理用户的key结果] ********************************************************************************************ok: [10.0.0.8] => { "msg": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCO72al73U2cAN6LjggrvY6ufhTf4m4IcR+ZkhHlk+NyFjYZ4aVNOmFRk1GZlNupMX2ZFe6BOXEPiKjLQHhYbrb7w29OAwq/IFhIzgLmURvn8yKcWV7+RAmJ6ZLbNw21ogqHAEOamUCvLi8GAnKPFFy+vcA86F6OQZjoP/GWA34r9ojjLHoQdxaokHujqzZZYbVMAKYEFSl6CHHoo14AIMiIoafchw8mgAyAr+uFRze5PJjNQ2o86jZUlBwBuHxrhyaYdx7p/sNRh/AjfVjZv5abHb4N5HzXofqjxOgsdgN9Ogm8yFt9gDypuVsb/8C1akiXG5o5aQhvYygG4xGtK7n ansible-generated on ubuntu2204.wang.org"}ok: [10.0.0.200] => { "msg": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCO72al73U2cAN6LjggrvY6ufhTf4m4IcR+ZkhHlk+NyFjYZ4aVNOmFRk1GZlNupMX2ZFe6BOXEPiKjLQHhYbrb7w29OAwq/IFhIzgLmURvn8yKcWV7+RAmJ6ZLbNw21ogqHAEOamUCvLi8GAnKPFFy+vcA86F6OQZjoP/GWA34r9ojjLHoQdxaokHujqzZZYbVMAKYEFSl6CHHoo14AIMiIoafchw8mgAyAr+uFRze5PJjNQ2o86jZUlBwBuHxrhyaYdx7p/sNRh/AjfVjZv5abHb4N5HzXofqjxOgsdgN9Ogm8yFt9gDypuVsb/8C1akiXG5o5aQhvYygG4xGtK7n ansible-generated on ubuntu2204.wang.org"}TASK [在被控端上创建用户] ***********************************************************************************************ok: [10.0.0.200]changed: [10.0.0.8]TASK [在被控端上创建用户.ssh目录] *****************************************************************************************ok: [10.0.0.200]changed: [10.0.0.8]TASK [将管理端 ssh_demo 用户的key存储到被控端] ******************************************************************************changed: [10.0.0.200]changed: [10.0.0.8]TASK [配置被控制端sudo提权] *************************************************************************************changed: [10.0.0.200]changed: [10.0.0.8]PLAY RECAP *****************************************************************************************************10.0.0.200 : ok=6 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 10.0.0.8 : ok=7 changed=5 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 #查看10.0.0.200[root@ubuntu2204 ansible]#getent passwd[root@ubuntu2204 ansible]#su - ssh_demo$ ssh 10.0.0.8The authenticity of host '10.0.0.8 (10.0.0.8)' can't be established.ED25519 key fingerprint is SHA256:rziuY3aU2QPQ9Aj+y//KUMlP8fkRzlREsMZcUn2sRuk.This key is not known by any other namesAre you sure you want to continue connecting (yes/no/[fingerprint])? yesWarning: Permanently added '10.0.0.8' (ED25519) to the list of known hosts.[ssh_demo@rocky8 ~]$exitlogoutConnection to 10.0.0.8 closed.$ ssh 10.0.0.8Last login: Wed Dec 21 20:52:30 2022[ssh_demo@rocky8 ~]$[root@ubuntu2204 ansible]#cat /home/ssh_demo/.ssh/id_rsa.pub ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCO72al73U2cAN6LjggrvY6ufhTf4m4IcR+ZkhHlk+NyFjYZ4aVNOmFRk1GZlNupMX2ZFe6BOXEPiKjLQHhYbrb7w29OAwq/IFhIzgLmURvn8yKcWV7+RAmJ6ZLbNw21ogqHAEOamUCvLi8GAnKPFFy+vcA86F6OQZjoP/GWA34r9ojjLHoQdxaokHujqzZZYbVMAKYEFSl6CHHoo14AIMiIoafchw8mgAyAr+uFRze5PJjNQ2o86jZUlBwBuHxrhyaYdx7p/sNRh/AjfVjZv5abHb4N5HzXofqjxOgsdgN9Ogm8yFt9gDypuVsb/8C1akiXG5o5aQhvYygG4xGtK7n ansible-generated on ubuntu2204.mooreyxia.org查看10.0.0.8[root@rocky8 ~]#getent passwdssh_demo:x:1002:1002::/home/ssh_demo:/bin/bash[root@rocky8 ~]#cat /home/ssh_demo/.ssh/authorized_keys ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCO72al73U2cAN6LjggrvY6ufhTf4m4IcR+ZkhHlk+NyFjYZ4aVNOmFRk1GZlNupMX2ZFe6BOXEPiKjLQHhYbrb7w29OAwq/IFhIzgLmURvn8yKcWV7+RAmJ6ZLbNw21ogqHAEOamUCvLi8GAnKPFFy+vcA86F6OQZjoP/GWA34r9ojjLHoQdxaokHujqzZZYbVMAKYEFSl6CHHoo14AIMiIoafchw8mgAyAr+uFRze5PJjNQ2o86jZUlBwBuHxrhyaYdx7p/sNRh/AjfVjZv5abHb4N5HzXofqjxOgsdgN9Ogm8yFt9gDypuVsb/8C1akiXG5o5aQhvYygG4xGtK7n ansible-generated on ubuntu2204.mooreyxia.org

Yaml 文件的相互调用

#利用include 或 include_tasks 可以在某个task中调用其它的只有task内容的yaml文件案例:[root@ansible ansible]#cat a.yml---- hosts: webservers tasks: - name: run a job command: wall run a job - name: excute b.yml include: b.yml #调用另一个yaml文件 #include_tasks: b.yml #另一种写法[root@ansible ansible]#cat b.yml- name: run b job command: wall run b job #import_playbook 可以将多个包含完整内容的yml文件由一个yml统一调用案例:[root@ansible ansible]#cat main.yml- import_playbook: tasks1.yml- import_playbook: tasks2.yml[root@ansible ansible]#cat tasks1.yml---- hosts: webservers tasks: - name: run task1 job command: wall run task1 job[root@ansible ansible]#cat tasks2.yml---- hosts: dbservers tasks: - name: run task2 job command: wall run task2 job[root@ansible ansible]#ansible-play main.yml

Roles 角色

34-Ansible常用playbook和大型项目role角色拆分_Roles

roles就是通过分别将变量、文件、任务、模板及处理器放置于单独的目录中,并可以便捷地include它们的一种机制

运维复杂的场景:建议使用 roles,代码复用度高

#roles:多个角色的集合目录, 可以将多个的role,分别放至roles目录下的独立子目录中,如下示例roles/ mysql/ nginx/ tomcat/ redis/ #默认roles存放路径/root/.ansible/roles/usr/share/ansible/roles/etc/ansible/roles#roles目录结构:playbook1.ymlplaybook2.ymlroles/ project1/ tasks/ files/ vars/ templates/ handlers/ defaults/ meta/ project2/ tasks/ files/ vars/ templates/ handlers/ defaults/ meta/

Roles各目录作用

roles/project/ :项目名称,有以下子目录

  • files/ :存放由copy或script模块等调用的文件
  • templates/:template模块查找所需要模板文件的目录
  • tasks/:定义task,role的基本元素,至少应该包含一个名为main.yml的文件;其它的文件需要在此文件中通过include进行包含
  • handlers/:至少应该包含一个名为main.yml的文件;此目录下的其它的文件需要在此文件中通过include进行包含
  • vars/:定义变量,至少应该包含一个名为main.yml的文件;此目录下的其它的变量文件需要在此文件中通过include进行包含,也可以通过项目目录中的group_vars/all定义变量,从而实现角色通用代码和项目数据的分离
  • meta/:定义当前角色的特殊设定及其依赖关系,至少应该包含一个名为main.yml的文件,其它文件需在此文件中通过include进行包含defaults/:设定默认变量时使用此目录中的main.yml文件,比vars的优先级低

创建role的步骤

1 创建role的目录结构.在以roles命名的目录下分别创建以各角色名称命名的目录,如mysql等,在每个角色命名的目录中分别创建相关的目录和文件,比如tasks、files、handlers、templates和vars等目录;用不到的目录可以创建为空目录,也可以不创建2 编写和准备指定role的功能文件,包括: tasks,templates,vars等相关文件3 编写playbook文件调用上面定义的role,应用到指定的主机

针对大型项目使用Roles进行编排

案例:实现 Nginx 角色[root@ansible ~]#mkdir -pv/data/ansible/roles/nginx/{tasks,handlers,templates,vars}#创建task文件[root@ansible ~]#cd /data/ansible/roles/nginx/[root@ansible nginx]#vim tasks/main.yml- include: install.yml- include: config.yml- include: index.yml- include: service.yml[root@ansible nginx]#vim tasks/install.yml- name: install yum: name=nginx[root@ansible nginx]#vim tasks/config.yml- name: config file for centos7 template: src=nginx7.conf.j2 dest=/etc/nginx/nginx.conf when: ansible_distribution_major_version=="7" notify: restart- name: config file for centos8 template: src=nginx8.conf.j2 dest=/etc/nginx/nginx.conf when: ansible_distribution_major_version=="8" notify: restart#跨角色调用文件[root@ansible nginx]#vim tasks/index.yml- name: index.html copy: src=roles/httpd/files/index.html dest=/usr/share/nginx/html/[root@ansible nginx]#vim tasks/service.yml- name: start service service: name=nginx state=started enabled=yes#创建handler文件[root@ansible nginx]#cat handlers/main.yml- name: restart service: name=nginx state=restarted#创建两个template文件[root@ansible nginx]#cat templates/nginx7.conf.j2...省略...user {{user}};worker_processes {{ansible_processor_vcpus+3}}; #修改此行error_log /var/log/nginx/error.log;pid /run/nginx.pid;...省略...[root@ansible nginx]#cat templates/nginx8.conf.j2...省略...user {{user}};worker_processes {{ansible_processor_vcpus**3}}; #修改此行error_log /var/log/nginx/error.log;pid /run/nginx.pid;...省略...#创建变量文件[root@ansible nginx]#vim vars/main.ymluser: daemon#目录结构如下[root@ansible ~]#tree /data/ansible/roles/nginx//data/ansible/roles/nginx/├── handlers│ └── main.yml├── tasks│ ├── config.yml│ ├── file.yml│ ├── install.yml│ ├── main.yml│ └── service.yml├── templates│ ├── nginx7.conf.j2│ └── nginx8.conf.j2└── vars└── main.yml4 directories, 9 files#在playbook中调用角色[root@ansible ~]#vim /data/ansible/role_nginx.yml---#nginx role- hosts: webservers roles: - role: nginx#运行playbook[root@ansible ~]#ansible-playbook /data/ansible/role_nginx.yml

我是moore,大家一起加油!

【本文转自:香港高防服务器 http://www.558idc.com/hkgf.html 复制请保留原URL】
网友评论