Linux入门DAY23

发布于:2025-08-14 ⋅ 阅读:(28) ⋅ 点赞:(0)

Linux入门DAY23

练习题

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

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

环境规划

主机角色 主机名 IP 地址 操作系统
控制节点 controller 10.1.8.10 CentOS 7
被控节点 1 node1 10.1.8.11 CentOS 7
被控节点 2 node2 10.1.8.12 CentOS 7
被控节点 3 node3 10.1.8.13 CentOS 7
被控节点 4 node4 10.1.8.14 CentOS 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}; do
  ssh-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: firewalld
        enabled: true
        state: started
    
    # 第四个任务
    - name: firewalld permits access to httpd service
      # firewalld,用于放行http服务
      firewalld:
        service: http
        permanent: true
        state: enabled
        immediate: yes
    
    # 第五个任务
    - name: httpd enabled and running
      # service模块,用于启用并启动httpd服务
      service:
        name: httpd
        enabled: true
        state: started

# Playbook中第二个play,-开头表示列表
- name: Test intranet web server
  hosts: localhost
  become: no
  tasks:
    - name: connect to intranet web server
      # uri模块,用于测试网站是否可以访问
      uri:
        url: http://node1
        return_content: yes
        status_code: 200

# yaml格式结束行,一般省略
...
yaml字典

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

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

fruit list:
	type1: banana
	type2: apple

Playbook 运行

#准备playbook剧本文件
[phoenix@controller ~ 16:25:00]$ cat playbook.yml 
---
- name: test vars statement in play
  hosts: node1
  vars:
    users:
      - user_name: phoenix1
        home_path: /home/phoenix1
      - user_name: phoenix2
        home_path: /home/phoenix2
  tasks:
    - 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.yml

playbook: 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 play
  3   hosts: node1     
  4   remote_user: phoenix
  5   become: true     
  6   become_method: sudo
  7   become_user: root
  8                                                                                         
  9   vars:
 10     users:
 11       - user_name: phoenix1
 12         home_path: /home/phoenix1
 13       - user_name: phoenix2
 14         home_path: /home/phoenix2
 15   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 play
  3   hosts: node1
  4   vars:
  5     user: user11
  6     home: /home/user11
  7   tasks:
  8     - name: add user {{ user }}
  9       user:
 10         name: "{{ user }}"
 11         home: "{{ home }}"
 12         state: present
 13  
 14     - name: debug user
 15       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.yml

 user: user1    
 home: /home/user1
 host: localhost  
 
#playbook声明
---                   
  2 - name: test vars statement in play
  3   hosts: node1        
  4   vars:               
  5     users:            
  6       - user_name: phoenix1      
  7         home_path: /home/phoenix1
  8       - user_name: phoenix2      
  9         home_path: /home/phoenix2
 10   vars_files:         
 11     - vars/config.yml     
Host scope

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

主机清单中定义
#声明父组子组
#node1 node2 webs子组
#node3 node4 dbs子组
[phoenix@controller ~ 18:45:25]$ vim inventory

controller
  2 [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_connection string smart 连接协议类型: • smart (自动选择) • sshparamiko (Python SSH库) 生产环境建议明确指定 ssh
ansible_host string inventory主机名 实际连接的主机地址/IP 优先使用DNS而非IP
ansible_port int 22 SSH端口号 非22端口需同步调整防火墙
ansible_user string 当前用户 SSH登录用户名 建议专用运维账户
ansible_ssh_pass string - SSH密码 ❌ 必须用Ansible Vault加密
ansible_ssh_private_key_file path ~/.ssh/id_rsa SSH私钥路径 权限应设为 600
ansible_ssh_common_args string - 全局SSH参数(影响scp/sftp/ssh) 示例:-o ProxyJump=bastion
ansible_sftp_extra_args string - SFTP额外参数 如带宽限制:-l 10240
ansible_scp_extra_args string - SCP额外参数 如压缩传输:-C
ansible_ssh_extra_args string - SSH额外参数 如禁用DNS检查:-o StrictHostKeyChecking=no
ansible_become bool false 是否提权 等价于旧版 ansible_sudo
ansible_become_method string sudo 提权方式: • sudosudoas 需目标系统支持
ansible_become_user string root 目标提权用户 非root用户需配置sudo权限
ansible_become_pass string - 提权密码 ❌ 必须用Ansible Vault加密
数组变量

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

#示例
---
- name: test vars statement in play
  hosts: node1
  vars:
    users:
      - user_name: phoenix1
        home_path: /home/phoenix1
      - user_name: phoenix2
        home_path: /home/phoenix2
  tasks:
    - 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 result
  hosts: node1
  tasks:
    - name: Install the package
      yum:
        name: httpd
        state: installed
      register: 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

网站公告

今日签到

点亮在社区的每一天
去签到