自动化运维 Ansible:不需要 Agent,SSH 批量部署

AI 概述
Ansible是无Agent自动化运维工具,通过YAML脚本实现批量服务器管理,大幅提升部署效率并降低失误。本文详解其优势、架构、安装配置、Inventory与SSH密钥设置,介绍Playbook编写、常用模块、变量、触发器及循环判断用法,给出最佳实践与常见误区,适合运维人员快速上手,实现应用批量部署与配置标准化。
目录
文章目录隐藏
  1. 一、为什么需要自动化运维?
  2. 二、Ansible 架构详解
  3. 三、安装与配置
  4. 四、第一个 Playbook
  5. 五、常用模块速查
  6. 六、变量管理
  7. 七、Handlers(触发器)
  8. 八、条件判断与循环
  9. 九、最佳实践
  10. 十、常见误区
  11. 十一、总结
  12. 结语

在服务器运维中,批量部署、配置管理等重复操作耗时费力,手动操作不仅效率低下,还易出现失误。Ansible 作为一款无 Agent、低学习成本的自动化运维工具,能通过简单的 YAML 脚本,快速实现多台服务器的统一管理,大幅提升运维效率、降低出错概率,是运维人员必备工具,以下为大家详细讲解其使用方法。

一、为什么需要自动化运维?

1.1 真实场景

场景 1:批量部署应用

你有 10 台服务器,需要部署 OpenClaw Gateway。

手动操作:
1. SSH 登录服务器 1
2. 安装 Node.js
3. 安装 OpenClaw
4. 配置文件
5. 启动服务
... 重复 10 遍

耗时:2 小时 × 10 = 20 小时
出错概率:高(手滑、配置写错)

Ansible 方案:

# 一个 Playbook 搞定
- hosts: all
  tasks:
  - name: 安装 Node.js
    apt:
      name: nodejs
      state: present
  - name: 安装 OpenClaw
    npm:
      name: openclaw
      global: yes
  - name: 启动服务
    systemd:
      name: openclaw
      state: started

执行:

ansible-playbook deploy.yml
# 10 台服务器同时部署
耗时:5 分钟
出错概率:低(自动化、幂等性)

1.2 Ansible 的优势

对比项 Ansible 其他工具(Puppet/Chef)
架构 无 Agent(SSH) 需要 Agent
学习曲线 低(YAML) 高(专用语言)
推送模式 推送(Push) 拉取(Pull)
幂等性 原生支持 需要额外配置
模块数量 3000+ 较少

通俗理解:

  • Ansible = 自动化 SSH 脚本工具。
  • 写一次 Playbook,到处运行。
  • 自动处理依赖、配置、服务。

1.3 适用场景

适合用 Ansible:

  • 批量部署应用。
  • 配置管理(统一配置)。
  • 批量执行命令。
  • CI/CD 部署。
  • 安全加固(批量打补丁)。

不适合用 Ansible:

  • 容器编排(用 K8s)。
  • 实时监控(用 Prometheus)。
  • 频繁变更(用配置中心)。

二、Ansible 架构详解

2.1 架构图

Ansible 架构图
Ansible 架构图【AI 生成】

2.2 核心概念

概念 说明 类比
控制节点 运行 Ansible 的机器 指挥中心
受管节点 被管理的服务器 执行单元
Inventory 主机列表配置文件 通讯录
Playbook 任务清单(YAML) 剧本
Play Playbook 中的一个阶段 一幕戏
Task 具体任务 一个动作
Module 执行模块 工具
Handler 触发式任务(服务重启等) 条件反射
Role 可复用的任务集合 模板

2.3 工作原理

1. 读取 Inventory(主机列表)
2. 读取 Playbook(任务清单)
3. 通过 SSH 连接受管节点
4. 推送 Module 到受管节点
5. 执行 Module(本地执行,结果返回)
6. 收集结果,输出报告

关键点:

  • 无 Agent:只需要 SSH,不需要在受管节点安装 Ansible。
  • 幂等性:多次执行结果一致(不会重复安装、重复配置)。
  • 模块化:3000+ 模块覆盖各种场景。

三、安装与配置

3.1 安装 Ansible

系统要求:

  • 控制节点:Python 3.9+;
  • 受管节点:Python 2.7+ 或 Python 3.5+、SSH Server。

Ubuntu/Debian:

# 添加官方仓库
sudo apt update
sudo apt install software-properties-common
sudo add-apt-repository --yes --update ppa:ansible/ansible

# 安装
sudo apt install ansible

# 验证
ansible --version
# 输出:ansible [core 2.16.x]

CentOS/RHEL:

# 添加 EPEL 仓库
sudo dnf install epel-release

# 安装
sudo dnf install ansible

# 验证
ansible --version

Mac(Homebrew):

brew install ansible
ansible --version

Windows(WSL):

# 在 WSL 中安装(推荐)
# 参考 Ubuntu 安装步骤

# 或使用 PowerShell(不推荐,功能受限)
pip install ansible

3.2 配置 SSH 密钥

为什么需要 SSH 密钥?

  • 免密码登录(自动化需要);
  • 更安全(比密码安全)。

生成密钥:

# 生成 RSA 密钥对
ssh-keygen -t rsa -b 4096 -C "ansible@control"

# 一路回车(不设密码,自动化需要)
# 输出:~/.ssh/id_rsa(私钥)
#       ~/.ssh/id_rsa.pub(公钥)

分发公钥到受管节点:

# 方式 1:使用 ssh-copy-id(推荐)
ssh-copy-id user@192.168.1.10
ssh-copy-id user@192.168.1.11

# 方式 2:手动复制
cat ~/.ssh/id_rsa.pub | ssh user@192.168.1.10 \
  "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"

# 验证
ssh user@192.168.1.10  # 应该免密码登录

测试 Ansible 连接:

# 测试所有主机
ansible all -m ping

# 输出:
# 192.168.1.10 | SUCCESS => {
#     "changed": false,
#     "ping": "pong"
# }

3.3 Inventory 配置

默认位置:/etc/ansible/hosts

方式 1:编辑默认文件

sudo vim /etc/ansible/hosts
# 简单列表
192.168.1.10
192.168.1.11
192.168.1.12

# 带用户名
web1.example.com ansible_user=admin
web2.example.com ansible_user=admin

# 带端口
db1.example.com ansible_port=2222

方式 2:分组管理(推荐)

# /etc/ansible/hosts

# Web 服务器组
[webservers]
web1.example.com
web2.example.com

# 数据库服务器组
[dbservers]
db1.example.com
db2.example.com

# 使用变量
[webservers]
web1.example.com http_port=80
web2.example.com http_port=8080

[dbservers]
db1.example.com db_port=5432
db2.example.com db_port=3306

# 组变量
[webservers:vars]
ansible_user=admin
ansible_python_interpreter=/usr/bin/python3

[dbservers:vars]
ansible_user=dba

方式 3:动态 Inventory(高级)

# 从云平台动态获取主机列表
# AWS、Azure、GCP、OpenStack 等都支持

# 示例:AWS EC2
ansible-inventory -i aws_ec2.yaml --list

方式 4:命令行指定

# 创建自定义 Inventory
cat > hosts.ini << EOF
[webservers]
192.168.1.10
192.168.1.11
EOF

# 使用
ansible-playbook -i hosts.ini deploy.yml

3.4 Ansible 配置

配置文件优先级:

  1. ./ansible.cfg(当前目录);
  2. ~/.ansible.cfg(用户目录);
  3. /etc/ansible/ansible.cfg(系统默认)。

常用配置:

# ansible.cfg
[defaults]
# Inventory 文件位置
inventory = ./hosts.ini

# 主机密钥检查(生产环境建议开启)
host_key_checking = False

# 并发数(默认 5)
forks = 10

# 超时时间
timeout = 30

# 日志文件
log_path = /var/log/ansible.log

# 角色路径
roles_path = ./roles

# 临时文件目录
remote_tmp = /tmp/ansible-${USER}

[privilege_escalation]
# 提权配置
become = True
become_method = sudo
become_user = root
become_ask_pass = False

四、第一个 Playbook

4.1 Playbook 结构

# deploy-nginx.yml
---
- name: 部署 Nginx Web 服务器
  hosts: webservers  # 目标主机组
  become: yes        # 提权为 root
  vars:              # 变量
    nginx_port: 80
    nginx_root: /var/www/html
  
  tasks:             # 任务列表
  - name: 安装 Nginx
    apt:
      name: nginx
      state: present
      update_cache: yes
  
  - name: 启动 Nginx 服务
    systemd:
      name: nginx
      state: started
      enabled: yes
  
  - name: 配置防火墙
    ufw:
      rule: allow
      port: "{{ nginx_port }}"
      proto: tcp
  
  - name: 创建首页
    copy:
      content: |
        <h1>Hello from Ansible!</h1>
        <p>Server: {{ inventory_hostname }}</p>
      dest: "{{ nginx_root }}/index.html"
  
  - name: 重启 Nginx(如果配置变化)
    systemd:
      name: nginx
      state: restarted
    when: nginx_config_changed  # 条件执行

4.2 运行 Playbook

# 基本运行
ansible-playbook deploy-nginx.yml

# 指定 Inventory
ansible-playbook -i hosts.ini deploy-nginx.yml

# 检查模式(不实际执行,只显示会做什么)
ansible-playbook deploy-nginx.yml --check

# 逐步确认执行
ansible-playbook deploy-nginx.yml --step

# 限制执行的主机
ansible-playbook deploy-nginx.yml --limit web1.example.com

# 传递变量
ansible-playbook deploy-nginx.yml --extra-vars "nginx_port=8080"

# 显示详细输出
ansible-playbook deploy-nginx.yml -v
ansible-playbook deploy-nginx.yml -vvv  # 更详细

4.3 完整示例:部署 OpenClaw Gateway

# deploy-openclaw.yml
---
- name: 部署 OpenClaw Gateway
  hosts: openclaw_servers
  become: yes
  vars:
    nodejs_version: "20.x"
    openclaw_version: "latest"
    gateway_port: 18789
  
  tasks:
  - name: 添加 Node.js 仓库
    apt_repository:
      repo: "deb https://deb.nodesource.com/node_{{ nodejs_version }} nodistro main"
      state: present
      update_cache: yes
  
  - name: 安装 Node.js
    apt:
      name: nodejs
      state: present
  
  - name: 安装 OpenClaw
    npm:
      name: openclaw
      version: "{{ openclaw_version }}"
      global: yes
  
  - name: 创建配置目录
    file:
      path: /opt/openclaw
      state: directory
      mode: '0755'
  
  - name: 部署配置文件
    template:
      src: templates/openclaw.json.j2
      dest: /opt/openclaw/openclaw.json
      mode: '0644'
    notify: restart openclaw
  
  - name: 创建 systemd 服务
    template:
      src: templates/openclaw.service.j2
      dest: /etc/systemd/system/openclaw.service
      mode: '0644'
    notify:
    - reload systemd
    - restart openclaw
  
  - name: 启动 OpenClaw 服务
    systemd:
      name: openclaw
      state: started
      enabled: yes
  
  - name: 配置防火墙
    ufw:
      rule: allow
      port: "{{ gateway_port }}"
      proto: tcp
  
  handlers:
  - name: reload systemd
    systemd:
      daemon_reload: yes
  
  - name: restart openclaw
    systemd:
      name: openclaw
      state: restarted

4.3 Template 文件

templates/openclaw.json.j2:

{
  "gateway": {
    "port": {{ gateway_port }},
    "bind": "0.0.0.0",
    "mode": "local"
  },
  "channels": {
    "feishu": {
      "appId": "{{ feishu_app_id }}",
      "appSecret": "{{ feishu_app_secret }}",
      "enabled": true
    }
  }
}

templates/openclaw.service.j2:

[Unit]
Description=OpenClaw Gateway
After=network.target

[Service]
Type=simple
User=openclaw
WorkingDirectory=/opt/openclaw
ExecStart=/usr/bin/openclaw gateway start
Restart=always

[Install]
WantedBy=multi-user.target

4.4 运行部署

# 运行 Playbook
ansible-playbook deploy-openclaw.yml

# 输出示例:
# PLAY [部署 OpenClaw Gateway] **************************************************
#
# TASK [Gathering Facts] ********************************************************
# ok: [192.168.1.10]
# ok: [192.168.1.11]
#
# TASK [添加 Node.js 仓库] *****************************************************
# changed: [192.168.1.10]
# changed: [192.168.1.11]
#
# TASK [安装 Node.js] ***********************************************************
# changed: [192.168.1.10]
# changed: [192.168.1.11]
#
# ...
#
# PLAY RECAP ********************************************************************
# 192.168.1.10               : ok=10   changed=8    unreachable=0    failed=0
# 192.168.1.11               : ok=10   changed=8    unreachable=0    failed=0

五、常用模块速查

5.1 包管理

apt(Debian/Ubuntu):

- name: 安装 Nginx
  apt:
    name: nginx
    state: present  # present/absent/latest

- name: 更新所有包
  apt:
    upgrade: dist
    update_cache: yes

- name: 添加仓库
  apt_repository:
    repo: "ppa:ansible/ansible"
    state: present

yum/dnf(CentOS/RHEL):

- name: 安装 Nginx
  yum:
    name: nginx
    state: present

- name: 添加 EPEL 仓库
  yum:
    name: epel-release
    state: present

npm:

- name: 安装 OpenClaw
  npm:
    name: openclaw
    global: yes
    state: present

pip:

- name: 安装 Python 包
  pip:
    name:
    - requests
    - flask
    state: present

5.2 文件管理

copy(复制文件):

- name: 复制配置文件
  copy:
    src: files/config.json
    dest: /opt/app/config.json
    mode: '0644'
    owner: app
    group: app
    backup: yes  # 备份原文件

template(模板渲染):

- name: 部署配置文件
  template:
    src: templates/config.json.j2
    dest: /opt/app/config.json
    mode: '0644'

file(管理文件属性):

- name: 创建目录
  file:
    path: /opt/app/data
    state: directory
    mode: '0755'
    owner: app
    group: app

- name: 删除文件
  file:
    path: /tmp/old-config.json
    state: absent

- name: 创建软链接
  file:
    src: /opt/app/config.json
    dest: /etc/app/config.json
    state: link

lineinfile(修改文件行):

- name: 修改 SSH 端口
  lineinfile:
    path: /etc/ssh/sshd_config
    regexp: '^#?Port'
    line: 'Port 2222'
    state: present

5.3 服务管理

systemd(服务管理):

- name: 启动 Nginx
  systemd:
    name: nginx
    state: started      # started/stopped/restarted/reloaded
    enabled: yes        # 开机自启
    daemon_reload: yes  # 重新加载 systemd 配置

service(通用服务管理):

- name: 启动服务
  service:
    name: nginx
    state: started

5.4 网络操作

get_url(下载文件):

- name: 下载文件
  get_url:
    url: https://example.com/file.tar.gz
    dest: /tmp/file.tar.gz
    checksum: sha256:abc123...  # 校验和
    mode: '0644'

uri(HTTP 请求):

- name: 检查 API
  uri:
    url: http://localhost:8080/health
    method: GET
    return_content: yes
    status_code: 200
  register: health_check

- name: 发送 POST 请求
  uri:
    url: https://api.example.com/deploy
    method: POST
    body_format: json
    body:
      version: "1.0.0"
    headers:
      Authorization: "Bearer {{ api_token }}"

5.5 命令执行

command(执行命令,不支持 shell 特性):

- name: 检查磁盘空间
  command: df -h /
  register: disk_usage

shell(执行 shell 命令,支持管道等):

- name: 获取系统信息
  shell: |
    uname -a
    cat /etc/os-release
  register: system_info
  changed_when: false  # 标记为不改变状态

- name: 等待服务就绪
  shell: curl -f http://localhost:8080/health
  register: result
  until: result.rc == 0
  retries: 10
  delay: 5

5.6 用户管理

user(用户管理):

- name: 创建用户
  user:
    name: openclaw
    shell: /bin/bash
    home: /home/openclaw
    groups: docker
    append: yes
    create_home: yes

- name: 设置 SSH 密钥
  authorized_key:
    user: openclaw
    key: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}"

5.7 调试模块

debug(输出信息):

- name: 显示变量
  debug:
    var: inventory_hostname

- name: 显示消息
  debug:
    msg: "部署到 {{ inventory_hostname }} 完成"

- name: 条件输出
  debug:
    msg: "这是生产环境"
  when: env == "production"

pause(暂停执行):

- name: 确认继续
  pause:
    prompt: "确认要重启服务吗?(Ctrl+C 取消)"

六、变量管理

6.1 变量优先级(从高到低)

1. 命令行变量(-e)
2. Play 中的 vars
3. host_vars/主机名
4. group_vars/组名
5. Inventory 变量
6. 角色默认变量
7. 事实变量(facts)

6.2 定义变量

方式 1:Play 中定义

- hosts: webservers
  vars:
    nginx_port: 80
    nginx_root: /var/www/html
  tasks: ...

方式 2:外部文件

- hosts: webservers
  vars_files:
    - vars/common.yml
    - vars/webservers.yml
  tasks: ...
# vars/common.yml
nginx_port: 80
nginx_root: /var/www/html

方式 3:group_vars

# group_vars/webservers.yml
nginx_port: 80
nginx_root: /var/www/html

# group_vars/dbservers.yml
db_port: 5432
db_user: postgres

方式 4:host_vars

# host_vars/web1.example.com.yml
nginx_port: 80
server_name: web1.example.com

# host_vars/web2.example.com.yml
nginx_port: 8080
server_name: web2.example.com

方式 5:Inventory 变量

[webservers]
web1.example.com nginx_port=80
web2.example.com nginx_port=8080

6.3 事实变量(Facts)

收集事实:

- hosts: all
  gather_facts: yes  # 默认开启
  tasks:
  - name: 显示系统信息
    debug:
      msg: |
        主机名:{{ ansible_hostname }}
        IP 地址:{{ ansible_default_ipv4.address }}
        操作系统:{{ ansible_distribution }} {{ ansible_distribution_version }}
        内存:{{ ansible_memtotal_mb }} MB
        CPU 核心:{{ ansible_processor_vcpus }}

常用 Facts:

ansible_hostname           # 主机名
ansible_fqdn              # 完整域名
ansible_default_ipv4      # 默认 IPv4 地址
ansible_distribution      # 发行版(Ubuntu/CentOS)
ansible_distribution_version  # 版本号
ansible_memtotal_mb       # 总内存(MB)
ansible_processor_vcpus   # CPU 核心数
ansible_architecture      # 架构(x86_64)

七、Handlers(触发器)

什么是 Handlers?

  • 特殊任务,只在被 notify 时执行;
  • 通常用于服务重启;
  • Play 结束时统一执行(多次 notify 只执行一次)。

示例:

tasks:
- name: 部署 Nginx 配置
  template:
    src: nginx.conf.j2
    dest: /etc/nginx/nginx.conf
  notify: restart nginx  # 配置变化时触发

- name: 更新 SSL 证书
  copy:
    src: ssl.crt
    dest: /etc/nginx/ssl/
  notify: restart nginx  # 再次触发(但只重启一次)

handlers:
- name: restart nginx
  systemd:
    name: nginx
    state: restarted

八、条件判断与循环

8.1 条件判断

when 语句:

tasks:
- name: 安装 Nginx(仅 Ubuntu)
  apt:
    name: nginx
    state: present
  when: ansible_distribution == "Ubuntu"

- name: 安装 Nginx(仅 CentOS)
  yum:
    name: nginx
    state: present
  when: ansible_distribution == "CentOS"

- name: 重启服务(仅生产环境)
  systemd:
    name: nginx
    state: restarted
  when: env == "production"

# 多条件
- name: 特殊配置
  template:
    src: special.conf.j2
    dest: /etc/app/special.conf
  when:
    - ansible_memtotal_mb > 4096
    - ansible_processor_vcpus > 4

8.2 循环

简单列表:

tasks:
- name: 创建多个用户
  user:
    name: "{{ item }}"
    state: present
  loop:
  - alice
  - bob
  - charlie

字典列表:

tasks:
- name: 安装多个包
  apt:
    name: "{{ item.name }}"
    state: "{{ item.state }}"
  loop:
  - { name: nginx, state: present }
  - { name: mysql, state: present }
  - { name: redis, state: absent }

嵌套循环:

tasks:
- name: 创建多个虚拟主机
  template:
    src: vhost.conf.j2
    dest: "/etc/nginx/sites-available/{{ item.0 }}-{{ item.1 }}.conf"
  loop: "{{ sites | product(ports) | list }}"
  vars:
    sites: ['site1', 'site2']
    ports: [80, 443]

九、最佳实践

9.1 目录结构

project/
├── ansible.cfg           # Ansible 配置
├── inventory/            # Inventory 文件
│   ├── production        # 生产环境
│   └── development       # 开发环境
├── group_vars/           # 组变量
│   ├── all.yml
│   └── webservers.yml
├── host_vars/            # 主机变量
│   └── web1.example.com.yml
├── playbooks/            # Playbook 文件
│   ├── deploy.yml
│   └── backup.yml
├── roles/                # Roles
│   ├── nginx/
│   └── mysql/
├── templates/            # Jinja2 模板
│   └── nginx.conf.j2
├── files/                # 静态文件
│   └── config.json
└── scripts/              # 辅助脚本
    └── validate.sh

9.2 幂等性原则

好的 Playbook:

- name: 确保 Nginx 运行
  systemd:
    name: nginx
    state: started
    enabled: yes
# 多次执行结果一致

不好的 Playbook:

- name: 启动 Nginx
  command: systemctl start nginx
# 每次执行都会标记为 changed

9.3 错误处理

tasks:
- name: 下载文件
  get_url:
    url: https://example.com/file.tar.gz
    dest: /tmp/file.tar.gz
  ignore_errors: yes  # 忽略错误继续执行
  register: download_result

- name: 使用备用下载地址
  get_url:
    url: https://backup.example.com/file.tar.gz
    dest: /tmp/file.tar.gz
  when: download_result.failed

9.4 标签(Tags)

tasks:
- name: 安装 Nginx
  apt:
    name: nginx
  tags:
  - nginx
  - install

- name: 配置 Nginx
  template:
    src: nginx.conf.j2
  tags:
  - nginx
  - config

# 只执行特定标签
ansible-playbook deploy.yml --tags nginx
ansible-playbook deploy.yml --tags config
ansible-playbook deploy.yml --skip-tags install

十、常见误区

误区 1:用 command 代替模块

错误:

- name: 安装 Nginx
  command: apt install nginx -y

正确:

- name: 安装 Nginx
  apt:
    name: nginx
    state: present

原因:模块有幂等性,command 每次都会执行。

误区 2:不处理错误

错误:

- name: 下载文件
  get_url:
    url: https://example.com/file.tar.gz
    dest: /tmp/file.tar.gz
# 下载失败继续执行

正确:

- name: 下载文件
  get_url:
    url: https://example.com/file.tar.gz
    dest: /tmp/file.tar.gz
  register: result
  failed_when: result.failed

- name: 清理
  file:
    path: /tmp/file.tar.gz
    state: absent
  when: result.failed

误区 3:硬编码变量

错误:

- name: 部署配置
  template:
    src: config.json.j2
    dest: /opt/app/config.json
# 端口、路径都写死在模板里

正确:

- hosts: all
  vars:
    app_port: 8080
    app_root: /opt/app
  tasks:
  - name: 部署配置
    template:
      src: config.json.j2
      dest: "{{ app_root }}/config.json"

十一、总结

核心要点

  1. 无 Agent:只需要 SSH,不需要在受管节点安装 Ansible;
  2. 幂等性:多次执行结果一致;
  3. 模块化:3000+ 模块覆盖各种场景;
  4. YAML:易读易写,学习曲线低。

检查清单

  • 配置 SSH 密钥(免密码登录);
  • 配置 Inventory(主机列表);
  • 测试连接(ansible all -m ping);
  • 编写第一个 Playbook;
  • 使用变量和模板;
  • 配置 Handlers;
  • 添加错误处理。

下一步学什么?

  1. Roles:可复用的任务集合;
  2. Ansible Vault:加密敏感信息;
  3. 动态 Inventory:从云平台获取主机列表;
  4. CI/CD 集成:GitHub Actions + Ansible;
  5. K8s 模块:用 Ansible 部署 Kubernetes 应用。

结语

本文从 Ansible 的核心价值、架构、安装配置,到 Playbook 编写、常用模块及最佳实践,全面覆盖入门必备知识。其无 Agent、幂等性、模块化的特点,能高效解决运维痛点。掌握基础用法后,可进一步学习 Roles、加密及云平台集成,逐步提升自动化运维能力,轻松应对各类运维场景。

以上关于自动化运维 Ansible:不需要 Agent,SSH 批量部署的文章就介绍到这了,更多相关内容请搜索码云笔记以前的文章或继续浏览下面的相关文章,希望大家以后多多支持码云笔记。

「点点赞赏,手留余香」

33

给作者打赏,鼓励TA抓紧创作!

微信微信 支付宝支付宝

还没有人赞赏,快来当第一个赞赏的人吧!

声明:本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若内容造成侵权/违法违规/事实不符,请将相关资料发送至 admin@mybj123.com 进行投诉反馈,一经查实,立即处理!
重要:如软件存在付费、会员、充值等,均属软件开发者或所属公司行为,与本站无关,网友需自行判断
码云笔记 » 自动化运维 Ansible:不需要 Agent,SSH 批量部署

发表回复