当前位置: 首页 > news >正文

Linux入门DAY23

Linux入门DAY23

练习题

你是某互联网公司的运维工程师,团队计划引入 Ansible 实现服务器集群的自动化管理(如批量部署服务、配置文件分发)。部署一套ansible实践环境,需要 1 台 Ansible 控制主机和 4 台被控主机,统一使用普通用户devops进行操作,要求:

  • 控制节点通过devops账户免密登录所有被控节点
  • 所有节点的devops账户可免密提权至 root(满足 Ansible 执行管理员操作的需求)
  • 环境基于 CentOS 7,确保后续 Ansible 剧本可正常运行

环境规划

主机角色主机名IP 地址操作系统
控制节点controller10.1.8.10CentOS 7
被控节点 1node110.1.8.11CentOS 7
被控节点 2node210.1.8.12CentOS 7
被控节点 3node310.1.8.13CentOS 7
被控节点 4node410.1.8.14CentOS 7

解题过程

  • 添加devops账户
  • 推送密钥
  • 提权root
  • 控制节点安装ansible
  • 准备测试清单
  • 准备ansible配置文件
  • 测试

所有节点创建devops用户

sudo useradd devops
echo "devops:devops" | sudo chpasswd

配置sudo免密(所有节点)

echo "devops ALL=(ALL) NOPASSWD:ALL" | sudo tee /etc/sudoers.d/devops
sudo chmod 440 /etc/sudoers.d/devops

控制节点生成SSH密钥

su - devops
ssh-keygen -t rsa -N "" -f ~/.ssh/id_rsa

配置SSH免密登录

for i in {1..4}; dossh-copy-id devops@node$i# 首次需要输入密码devops
done
# 包括控制节点自身
ssh-copy-id devops@controller

控制节点安装Ansible

sudo yum install -y epel-release
sudo yum install -y ansible

创建最小化inventory文件

cat > ~/hosts <<EOF
[nodes]
node1 ansible_host=10.1.8.11
node2 ansible_host=10.1.8.12
node3 ansible_host=10.1.8.13
node4 ansible_host=10.1.8.14[all:vars]
ansible_user=devops
ansible_ssh_private_key_file=/home/devops/.ssh/id_rsa
EOF

测试连接

ansible all -i ~/hosts -m ping
ansible nodes -i ~/hosts -m shell -a "sudo whoami"

Ansible

编写和运行 Playbook

环境准备

[phoenix@controller ~ 11:48:17]$ cat inventory 
controller
node1
node2
node3
node4

Playbook 介绍

  • playbook 是一个文本文件,作为执行剧本
  • adhoc 命令可以作为一次性命令对一组主机运行一项简单的任务。不过,若要真正发挥Ansible的能力,需要使用功能 playbook
  • Playbooks以yaml格式编写,通常以 yaml 和 yml 扩展名保存
  • yaml格式只使用空格缩进,对于空格的数量没有强制要求

基本规则:

  • 同一级别的元素,使用相同的缩进。
  • 对于子项目,使用比父项目更多的缩进。
  • 增加空白行,提高可读性
#编辑vim环境变量
[phoenix@controller ~ 11:52:35]$ vim ~/.vimrc#自动缩进
#十字定位
set ai ts=2
set cursorcolumn cursorline

Playbook 编写

# yaml格式起始行,一般不省略
---# Playbook中第一个play
# play具有属性:name,hosts,become,tasks,缩进一致
# name属性,用于简要描述play
- name: Enable intranet services# hosts属性,用于定义要在哪个受管理节点执行hosts: node1# tasks属性,用于描述play中任务,属性是列表格式tasks:# 第一个任务# 任务具有属性:涵name和模块名等。# name属性,用于简要描述任务- name: latest version of httpd and firewalld installed# 指明模块名,也就是要执行的任务yum:# 执行要操作的rpm包名称name:# rpm包名称是-开头的列表格式,或者逗号分隔的列表格式- httpd- firewalld# 定义软件包的状态,lastet代表升级为最新版本state: latest# 第二个任务- name: test html page is installed# copy模块,用于将content属性值写入到目标文件copy:content: "Welcome Laoma WebSite!\n"dest: /var/www/html/index.html# 第三个任务- name: firewalld enabled and running# service模块,用于启用并启动firewalld服务service:name: firewalldenabled: truestate: started# 第四个任务- name: firewalld permits access to httpd service# firewalld,用于放行http服务firewalld:service: httppermanent: truestate: enabledimmediate: yes# 第五个任务- name: httpd enabled and running# service模块,用于启用并启动httpd服务service:name: httpdenabled: truestate: started# Playbook中第二个play,-开头表示列表
- name: Test intranet web serverhosts: localhostbecome: notasks:- name: connect to intranet web server# uri模块,用于测试网站是否可以访问uri:url: http://node1return_content: yesstatus_code: 200# yaml格式结束行,一般省略
...
yaml字典

yaml中是以一组键值对的集合实现的,又称为映射

以缩进块的形式编写键值对集合

fruit list:type1: bananatype2: apple

Playbook 运行

#准备playbook剧本文件
[phoenix@controller ~ 16:25:00]$ cat playbook.yml 
---
- name: test vars statement in playhosts: node1vars:users:- user_name: phoenix1home_path: /home/phoenix1- user_name: phoenix2home_path: /home/phoenix2tasks:- name: add user {{ users.0.username }}user:name: "{{ users.0.user_name }}"home: "{{ users.0.home_path }}"- name: debug {{ users[1].user_name}}debug:msg: "{{ users[1].user_name }}"...
运行
[phoenix@controller ~ 16:25:19]$ ansible-playbook playbook.yml
PLAY [test vars statement in play] *********************************************************TASK [Gathering Facts] *********************************************************************
ok: [node1]TASK [add user {{ users.0.username }}] *****************************************************
ok: [node1]TASK [debug phoenix2] **********************************************************************
ok: [node1] => {"msg": "phoenix2"
}PLAY RECAP *********************************************************************************
node1                      : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0  
语法检查

当yaml文件出现错误,使用–syntax选项

[phoenix@controller ~ 18:01:55]$ ansible-playbook --syntax-check playbook.ymlplaybook: playbook.yml
空运行

空运行,是指模拟运行,并不是真正执行

[phoenix@controller ~ 18:01:59]$ ansible-playbook playbook.yaml -C

Playbook 提权

在playbook中指定关键字将覆盖/etc/ansible/ansible.cfg文件中的设置特权升级属性

  • remote_user,指定ssh用户

  • become,启用或禁用特权升级

  • become_method,启用特权升级的方法

  • become_user,特殊升级的帐户

---                2 - name: test vars statement in play3   hosts: node1     4   remote_user: phoenix5   become: true     6   become_method: sudo7   become_user: root8                                                                                         9   vars:10     users:11       - user_name: phoenix112         home_path: /home/phoenix113       - user_name: phoenix214         home_path: /home/phoenix215   tasks:
...          

管理变量和事实

环境准备

[phoenix@controller ~ 18:16:20]$ cat inventory 
controller
node1
node2
node3
node4[phoenix@controller ~ 18:16:29]$ cat ansible.cfg 
[defaults]
remote_user = phoenix
inventory = ./inventory[privilege_escalation]
become = True
become_user = root
become_method = sudo
become_ask_pass = False

管理VARIABLES

ansible 利用变量来存储数据,以便在项目中重复引用,我们可以在playbook针对操作定义

变量命名规则
  • 只能包含字母、数字和下划线(如包含空格、点、$符号都为非法变量名)
  • 只能**以字母开头*
变量优先级
  • Global scope:从命令行或 Ansible 配置设置的变量
  • Play scope:在play和相关结构中设置的变量
  • Host scope:由清单、事实(fact)收集或注册的任务,在主机组和个别主机上设置的变量

优先级从高到低顺序:Global -> Play -> Host

如果出现定义多个相同名称变量,最高级优先

变量引用
  • 变量名称的引用必须用{{}}符号,ansible会将变量替换为其值
  • 当变量用作值的第一元素时,变量引用必须使用引号
Global scope
#-m 指定模块
#-a 指定命令
#-e 传递全局变量 优先级最高
[phoenix@controller ~ 18:26:43]$ ansible node1 -m yum -a "name={{ package }} state=present" -e "package=tree"
node1 | SUCCESS => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": false, "msg": "", "rc": 0, "results": ["tree-1.6.0-10.el7.x86_64 providing tree is already installed"]
}
Play scope
#play scope 作用于当前 play 的所有 tasks---                                                                                     2 - name: test vars statement in play3   hosts: node14   vars:5     user: user116     home: /home/user117   tasks:8     - name: add user {{ user }}9       user:10         name: "{{ user }}"11         home: "{{ home }}"12         state: present13  14     - name: debug user15       debug:16         msg: |17           username is {{ user }}18           home is {{ home }}19 ...

当需要引用相当多的变量,可以对变量文件分类引用

[phoenix@controller ~ 18:39:35]$ mkdir vars
[phoenix@controller ~ 18:39:40]$ vim vars/config.ymluser: user1    home: /home/user1host: localhost  #playbook声明
---                   2 - name: test vars statement in play3   hosts: node1        4   vars:               5     users:            6       - user_name: phoenix1      7         home_path: /home/phoenix18       - user_name: phoenix2      9         home_path: /home/phoenix210   vars_files:         11     - vars/config.yml     
Host scope

主机变量应用与主机和主机组,主机变量优先级高于组变量

主机清单中定义
#声明父组子组
#node1 node2 webs子组
#node3 node4 dbs子组
[phoenix@controller ~ 18:45:25]$ vim inventorycontroller2 [nodes:children]                                                                        3 webs     4 dbs      5          6 [webs]   7 node1    8 node2    9          10 [dbs]    11 node3    12 node4    #验证[phoenix@controller ~ 18:54:34]$ ansible all -m debug -a 'var=node'
controller | SUCCESS => {"node": "VARIABLE IS NOT DEFINED!"
}
node1 | SUCCESS => {"node": "NODE1"
}
node2 | SUCCESS => {"node": "NODE2"
}
node3 | SUCCESS => {"node": "NODES"
}
node4 | SUCCESS => {"node": "NODES"
}
目录分层结构定义

在项目目录中创建如下目录:

  • group_vars,定义主机组变量
  • host_vars,定义主机变量
[phoenix@controller ~ 18:59:05]$ cat inventory 
controller
[nodes:children]
webs
dbs[webs]
node1
node2[dbs]
node3
node4

验证

var参数不需要引号引用

#node1所属主机组
[phoenix@controller ~ 19:09:57]$ ansible node1 -m debug -a var=group_names
node1 | SUCCESS => {"group_names": ["nodes", "webs"]
}#清单中所有主机组
[phoenix@controller ~ 19:10:02]$ ansible node1 -m debug -a var=groups
node1 | SUCCESS => {"groups": {"all": ["controller", "node1", "node2", "node3", "node4"], "dbs": ["node3", "node4"], "nodes": ["node1", "node2", "node3", "node4"], "ungrouped": ["controller"], "webs": ["node1", "node2"]}
}#特定主机组
[phoenix@controller ~ 19:12:49]$ ansible node1 -m debug -a var=groups.dbs
node1 | SUCCESS => {"groups.dbs": ["node3", "node4"]
}#查询所有主机变量信息
[phoenix@controller ~ 19:12:50]$ ansible node1 -m debug -a var=hostvars
主机连接特殊变量
参数名称类型默认值描述安全建议
ansible_connectionstringsmart连接协议类型: • smart (自动选择) • sshparamiko (Python SSH库)生产环境建议明确指定 ssh
ansible_hoststringinventory主机名实际连接的主机地址/IP优先使用DNS而非IP
ansible_portint22SSH端口号非22端口需同步调整防火墙
ansible_userstring当前用户SSH登录用户名建议专用运维账户
ansible_ssh_passstring-SSH密码❌ 必须用Ansible Vault加密
ansible_ssh_private_key_filepath~/.ssh/id_rsaSSH私钥路径权限应设为 600
ansible_ssh_common_argsstring-全局SSH参数(影响scp/sftp/ssh)示例:-o ProxyJump=bastion
ansible_sftp_extra_argsstring-SFTP额外参数如带宽限制:-l 10240
ansible_scp_extra_argsstring-SCP额外参数如压缩传输:-C
ansible_ssh_extra_argsstring-SSH额外参数如禁用DNS检查:-o StrictHostKeyChecking=no
ansible_becomeboolfalse是否提权等价于旧版 ansible_sudo
ansible_become_methodstringsudo提权方式: • sudosudoas需目标系统支持
ansible_become_userstringroot目标提权用户非root用户需配置sudo权限
ansible_become_passstring-提权密码❌ 必须用Ansible Vault加密
数组变量

通过使用[‘’]引用方式可以避免与python功能函数重名冲突

#示例
---
- name: test vars statement in playhosts: node1vars:users:- user_name: phoenix1home_path: /home/phoenix1- user_name: phoenix2home_path: /home/phoenix2tasks:- name: add user {{ users.0.username }}user:name: "{{ users.0.user_name }}"home: "{{ users.0.home_path }}"- name: debug {{ users[1].user_name}}debug:msg: "{{ users[1].user_name }}"...
register 语句

**register 语句捕获任务输出。**输出保存在一个临时变量中,稍后在playbook中可用于调试用途或者达成其他目的

[phoenix@controller ~ 19:18:26]$ cat playbook1.yml 
---
- name: Installs a package and prints the resulthosts: node1tasks:- name: Install the packageyum:name: httpdstate: installedregister: install_result- debug: var: install_result
...
MAGIC 变量

magic 变量由 Ansible 自动设置,可用于获取与特定受管主机相关的信息

#当前环境
[phoenix@controller ~ 19:23:58]$ cat inventory 
controller[webs]
node1
node2[dbs]
node3
node4
  • inventory_hostname包含配置中当前受管主机的主机名称

    [phoenix@controller ~ 19:24:00]$ ansible node1 -m debug -a var=inventory_hostname
    node1 | SUCCESS => {"inventory_hostname": "node1"
    }
    
  • group_names列出当前受管主机所属的所有主机组

    [phoenix@controller ~ 19:26:42]$ ansible node1 -m debug -a var=group_names
    node1 | SUCCESS => {"group_names": ["webs"]
    }
    
  • groups,列出清单中的所有组,以及组中含有的主机。

    [phoenix@controller ~ 19:26:43]$ ansible node1 -m debug -a var=groups
    node1 | SUCCESS => {"groups": {"all": ["controller", "node1", "node2", "node3", "node4"], "dbs": ["node3", "node4"], "ungrouped": ["controller"], "webs": ["node1", "node2"]}
    }
    
  • hostvars,包含所有受管主机的变量,可用于获取另一台受管主机的变量的值

[phoenix@controller ~ 19:31:05]$ ansible node1 -m debug -a var=hostvars | head
node1 | SUCCESS => {"hostvars": {"controller": {"ansible_check_mode": false, "ansible_diff_mode": false, "ansible_facts": {}, "ansible_forks": 5, "ansible_inventory_sources": ["/home/phoenix/inventory"], 

需求 在node1主机上获取node2所属主机组

[phoenix@controller ~ 19:32:57]$ ansible node1 -m debug -a var=hostvars.node2.group_names
node1 | SUCCESS => {"hostvars.node2.group_names": ["nodes", "webs"]
}

管理 SECRETS

ansible-vault

在ansible传递参数过程中,密钥是以纯文本明文方式显示,这样存在安全风险,需要用到ansible vault加密数据

ansible-vault 命令
命令作用
create新建一个由 Ansible Vault 加密的文件(默认使用 AES256 加密)
decrypt将加密文件解密为明文(需提供加密时的密码)
edit直接编辑加密文件(保存后自动重新加密)
view查看加密文件内容(不修改文件)
encrypt对普通 YAML 文件进行加密
encrypt_string直接加密字符串(用于嵌入 Playbook 或变量文件)
rekey修改加密文件的密码(需提供旧密码和新密码)

**示例 **

#create加密文件
[phoenix@controller ~ 16:02:59]$ ansible-vault create user.yaml
New Vault password: 
Confirm New Vault password: #加密后cat命令是以密文方式显示
[phoenix@controller ~ 16:07:09]$ cat user.yaml 
$ANSIBLE_VAULT;1.1;AES256
38313530396533323730336665316265386262346163623038663237326130343436326662353732
3539663339386335626537366339623730366130613939380a333837373666303132663736613962
35626263356364333735303634303034393631336365346430636462653330653061386334393537
3966666637663036300a343937303138616164323261623534633735326437383432646466333333
36323031643930653261643836653939336437633764373631326437323161303231383161626163
39366464626638306336353034383434373837313537643564636266346362356264663836663863
62623964656434366563663935333231366165393763393237363365316164313036306561353237
30626431646232376530#使用view参数 输入密码后显示明文
[phoenix@controller ~ 16:07:16]$ ansible-vault view user.yaml 
Vault password: 
login_name: phoenix     
login_passwd: 1
login_host: 10.1.8.11
login_type: ssh#解密
[phoenix@controller ~ 16:07:32]$ ansible-vault decrypt user.yaml 
Vault password: 
Decryption successful#cat明文
[phoenix@controller ~ 16:07:51]$ cat user.yaml 
login_name: phoenix	
login_passwd: 1
login_host: 10.1.8.11
login_type: ssh#再次加密
[phoenix@controller ~ 16:07:55]$ ansible-vault encrypt user.yaml 
New Vault password: 
Confirm New Vault password: 
Encryption successful
[phoenix@controller ~ 16:08:20]$ cat user.yaml 
$ANSIBLE_VAULT;1.1;AES256
37666337373634346165393663383032613931636139656535633562373838393764326235643261
3663663361353463343866643762383539373039396564650a393030616130343332306466303338
38653737626666613362313265643962643865373365663761626134366232363731386565356232
3035653233313065610a623263326436656436303831313461636139613463383835383261656532
35373033646137383137333236663333333366613436356131393565353864373262323933656132
35623964303331666131323636356661633633326336303539363332366563343732306439366232
31316435626661353139653338343563356436303137646237633535613838386566623231316430
31323630643839393638#更改密码
[phoenix@controller ~ 16:08:27]$ ansible-vault rekey user.yaml 
Vault password: 
New Vault password: 
Confirm New Vault password: 
Rekey successful
http://www.lryc.cn/news/619433.html

相关文章:

  • 【从零开始java学习|第五篇】项目、模块、包、类的概念与联系
  • 解决:Gazebo连接模型数据库失败
  • 制作一款打飞机游戏90:完结
  • JavaSE高级-01
  • BGP 笔记梳理
  • 分布式事务DTP模型
  • Vue3 vs Vue2:全面对比与面试宝典
  • 递归函数与 lambda 函数:用法详解与实践
  • Pixelorama 1.1.3 像素动画编辑制作
  • 科普:Pygame 中的坐标系
  • 猫头虎AI分享:Excel MCP,让AI具备操作Excel表格|创建销售数据表、复制工作表、填充数据、写公式、绘制图表、调节颜色、添加透视表、保存为PDF
  • python与JavaScript的区别
  • Unity3d UGUI图片按钮只有非透明区域(透明阈值)可以点击功能实现(含源码)
  • 高级IO(五种IO模型介绍)
  • C# 多线程:并发编程的原理与实践
  • I2c、SPI、USB驱动架构类比
  • 2025年,Javascript后端应该用 Bun、Node.js 还是 Deno?
  • 欧姆龙E6B2-CWZ6C旋转编码器参数说明+示例代码
  • SQL详细语法教程(二)--DML(数据操作语言)和DQL(数据查询语言)
  • PostgreSQL——索引
  • 【Unity3D】Spine黑线(预乘问题)、贴图边缘裁剪问题
  • django request.data.get 的值修改
  • 基于Tensorflow2.15的图像分类系统
  • C++中的`auto`与`std::any`:功能、区别与选择建议
  • Android 在 2020-2025 都做哪些更新?
  • 从0开始跟小甲鱼C语言视频使用linux一步步学习C语言(持续更新)8.13
  • 数据治理之元数据管理
  • TensorFlow实现回归分析详解
  • PyTorch基础(使用TensorFlow架构)
  • CSS counter-reset 与 counter-increment:用 CSS 实现自动编号的黑科技