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

自动化运维Ansible

目录

    • 一、介绍
      • 1. 自动化运维工具对比
      • 2. Ansible 简介与特性
      • 3. 变量优先级(从高到低)
    • 二、Ansible 安装(CentOS 7)
      • 1. 环境准备
      • 2. 安装步骤
      • 3. 基础配置与 Inventory
    • 三、Ad-Hoc 命令与常用模块
      • 命令格式与常用选项
      • ping 探活
      • shell vs command
      • copy 复制与备份
      • user 用户管理
      • yum 包管理
      • service 服务管理
      • file 文件/目录/链接
      • script 远程执行本地脚本
      • setup 收集 Facts
      • archive 打包
      • unarchive 解压
      • cron 定时任务
      • get_url 下载文件
      • yum_repository 管理仓库源
      • lineinfile 修改/插入行
      • debug 调试输出
    • 四、Ansible Playbook 剧本
      • Playbook 基础与结构
      • 基础命令/输出颜色含义
      • Tasks 示例
      • Handlers/Notify 触发器
      • 循环/迭代(with_items/loop)
      • 自定义变量与 vars_files
      • 分组与多 Play 示例(group 模块)
      • gather_facts 与变量示例
      • debug 调试 Playbook
      • 条件判断 when
    • 五、项目综合实战:Nginx + PHP Web 部署(CentOS 7)
      • 1. 目标与架构
      • 2. 目录结构
      • 3. 基础配置与清单
      • 4. 角色实现(common/nginx/php/app)
      • 5. site.yml 编排与运行
      • 6. 回滚与验证要点

一、介绍

1. 自动化运维工具对比

  • Puppet:基于 Ruby,C/S 架构,可扩展强;远程命令执行偏弱。
  • SaltStack:基于 Python,C/S 架构,较轻量,配置用 YAML;需要在每台被控端安装 agent。
  • Ansible:基于 Python,分布式,无客户端,轻量;YAML + Jinja2;远程命令执行强。默认通过 SSH 连接。

通俗理解:Ansible 更容易“开箱即用”,无需在被控端安装东西(免 agent),非常适合快速批量操作与配置编排。

2. Ansible 简介与特性

  • Ansible 是自动化运维工具,基于模块工作(核心是模块,Ansible 负责编排和分发调用)。
  • 特性:
    1. no agents:被控端无需安装客户端;升级只需升级控制端。
    2. no server:无中心服务端,直接用命令/剧本即可。
    3. modules in any languages:模块可用任意语言实现。
    4. yaml, not code:用 YAML 写剧本(Playbook),更易读。
    5. ssh by default:默认基于 SSH 连接。
  • 组件简述:
    • connection plugins:连接插件,默认 SSH。
    • host inventory:主机清单,定义被控主机与分组。
    • modules:模块(command、copy、user…)。
    • plugins:插件(连接、回调、邮件等)。
    • playbook:编排多任务的 YAML 定义。
  • 默认并发数:5(可在 ansible.cfg 中调整 forks)。

3. 变量优先级(从高到低)

  1. 命令行变量:-e/--extra-vars(最高)。
  2. Inventory 中的主机/组变量。
  3. Playbook 内的 varsvars_files
  4. Facts(setup 收集)。
  5. 角色的默认变量:roles/*/defaults/main.yml 最低。

注:新写法建议使用 ansible_user/ansible_password/ansible_port/ansible_ssh_private_key_file,不再推荐旧名 ansible_ssh_user/ansible_ssh_pass(兼容但逐步淘汰)。


二、Ansible 安装(CentOS 7)

1. 环境准备

  • 关闭防火墙与 SELinux(生产建议按需放行端口而非直接关闭,这里为教学简化)。
  • 控制节点 1 台,被控节点若干。示例:
# /etc/hosts(各机均添加,便于主机名解析)
192.168.1.10 ansible-web1
192.168.1.11 ansible-web2
192.168.1.12 ansible-web3
192.168.1.9  ansible-server   # 控制端
  • SSH 免密:在控制端生成密钥并分发至各被控端。
ssh-keygen -t rsa -b 4096 -C "ansible@server"
ssh-copy-id -i ~/.ssh/id_rsa.pub 192.168.1.10
ssh-copy-id -i ~/.ssh/id_rsa.pub 192.168.1.11
ssh-copy-id -i ~/.ssh/id_rsa.pub 192.168.1.12

提示:无免密也可用密码登录,但不便于自动化;建议配置免密。

2. 安装步骤

CentOS 7 默认 Python 2.7,但新版本 Ansible 更推荐 Python 3。常见两种方式:

  • 方式 A(简单):EPEL + yum 安装 Ansible(一般为 2.9.x),可在 Python 2.7 下运行。
yum install -y epel-release
yum install -y ansible
ansible --version
ansible --help
  • 方式 B(推荐):安装 Python 3(EPEL 或 IUS),用 pip 安装较新 Ansible。
yum install -y epel-release
yum install -y python36 python3-pip
pip3 install --upgrade pip
pip3 install "ansible<8"   # 在 CentOS 7 上兼容较佳的版本区间
ansible --version

说明:CentOS 7 年代较老,新版 Ansible 可能依赖较新 Python;如遇依赖冲突,选择方式 A 或锁定版本。

3. 基础配置与 Inventory

  • 查看默认配置文件位置:
rpm -qc ansible
# /etc/ansible/ansible.cfg
# /etc/ansible/hosts
  • 主配置:/etc/ansible/ansible.cfg(日志、forks、模块路径、回调插件等)。
  • 主机清单:/etc/ansible/hosts(建议直接使用 IP,避免 DNS 依赖)。

示例(单主机与分组):

# 直接添加主机
ansible-web1# 添加主机组
[webservers]
192.168.1.11
ansible-web2# 组合组(children)
[webservers1]
ansible-web1[webservers2]
ansible-web2[weball:children]
webservers1
webservers2# 组变量(组内主机均生效)
[weball:vars]
ansible_user=root
ansible_port=22
# 使用私钥(如路径非默认时设置)
# ansible_ssh_private_key_file=/root/.ssh/id_rsa
# 若无免密,也可用密码(不安全,演示用)
# ansible_password=your_password

查看组内主机:

ansible weball --list-hosts

使用自定义 Inventory(文件 /opt/hostlist):

[all:vars]
ansible_user=root
ansible_port=22
# ansible_password=your_password[all]
ansible-web1
ansible-web2

执行时指定:

ansible -i /opt/hostlist all -m ping -o

提示:ping 模块是 SSH 探活(非 ICMP),等价于“能否连上 22 端口并执行模块”。


三、Ad-Hoc 命令与常用模块

命令格式与常用选项

ansible <pattern> -m <module_name> -a <arguments> [其他选项]
  • pattern:主机/组名/IP/别名,all 为全部;支持通配与正则。
  • -m:模块名,默认 command
  • -a:模块参数。
  • -o:单行输出(更紧凑)。

ping 探活

# 单台
ansible ansible-web1 -m ping -o
# 多台
ansible ansible-web1,ansible-web2 -m ping -o
# 组
ansible webservers1 -m ping -o

shell vs command

  • shell:支持管道、重定向、通配符;适合复杂命令链。
  • command:直接执行命令,不经 shell;更高效/安全。
# 两者等效示例(简单命令)
ansible webservers1 -m shell -a 'uptime'
ansible webservers1 -a 'uptime'   # 默认 command

copy 复制与备份

常用参数:src/dest/owner/group/mode/backup

# 控制端 /root/a.txt -> 远端 /opt/ (保留权限)
ansible weball -m copy -a 'src=/root/a.txt dest=/opt owner=root group=root mode=0644' -o
# 覆盖时备份
ansible weball -m copy -a 'src=/root/a.txt dest=/opt/ owner=root group=root mode=0644 backup=yes' -o

user 用户管理

# 添加/删除用户
ansible ansible-web1 -m user -a "name=qianfeng"
ansible ansible-web1 -m user -a "name=qianfeng state=absent" -o
ansible ansible-web1 -m user -a "name=qianfeng state=absent remove=yes"  # 连同家目录/邮件删除# 设置密码(需哈希值,而非明文)
python - <<'PY'
import crypt
print(crypt.crypt('12345678'))
PY
# 假设输出为 $6$.... 形如 /etc/shadow 的哈希
ansible ansible-web1 -m user -a "name=tom password='$6$...'"# 生成 SSH 密钥对(在被控端为该用户创建 ~/.ssh/id_rsa*)
ansible ansible-web1 -m user -a "name=tom generate_ssh_key=yes"

yum 包管理

# 安装 httpd(最新)
ansible webservers1 -m yum -a "name=httpd state=latest" -o
# 卸载 httpd
ansible webservers1 -m yum -a "name=httpd state=removed" -o

常见 state

  • latest:安装最新
  • present/installed:确保已安装
  • absent/removed:卸载

service 服务管理

ansible webservers1 -m service -a "name=httpd state=started"      # 启动
ansible webservers1 -m service -a "name=httpd state=stopped"      # 停止
ansible webservers1 -m service -a "name=httpd state=restarted"    # 重启
ansible webservers1 -m service -a "name=httpd state=started enabled=yes" # 开机自启

提示:CentOS 7 使用 systemd;某些模块也支持 enabled 单独设置。

file 文件/目录/链接

# 创建空文件
ansible webservers1 -m file -a 'path=/tmp/88.txt mode=0777 state=touch'
# 创建目录
ansible webservers1 -m file -a 'path=/tmp/99 mode=0777 state=directory'

更多 Playbook 写法(更可读):

- name: Ensure testfile existsfile:path: /tmp/testfilestate: touch- name: Ensure testdir existsfile:path: /tmp/testdirstate: directoryowner: myusergroup: mygroupmode: '0755'- name: Remove testfilefile:path: /tmp/testfilestate: absent- name: Create a symlinkfile:src: /tmp/originaldest: /tmp/linkstate: link- name: Recursively chmodfile:path: /tmp/testdirstate: directorymode: '0755'recurse: yes

script 远程执行本地脚本

适合“控制端有脚本,但被控端没有”的场景。Ansible 会把脚本临时传到远端执行。

# 本地脚本
cat > /root/test.sh <<'SH'
#!/usr/bin/env bash
touch test{1..50}
SH
chmod +x /root/test.sh# 在远端 /mnt 目录下执行该脚本
ansible webservers1 -m script -a "chdir=/mnt /root/test.sh"# 条件执行示例(存在某文件才执行/或不存在才执行)
cat > /root/awk.sh <<'SH'
#!/usr/bin/env bash
awk -F: '{print $1,$2}' /etc/passwd
SH
chmod +x /root/awk.shansible webservers1 -m script -a "/root/awk.sh removes=/etc/passwd"

说明:removes=/path 表示当该路径存在时才执行;creates=/path 表示当该路径存在时跳过执行。

setup 收集 Facts

# 收集全部 facts
ansible webservers1 -m setup
# 仅过滤 IPv4 地址
ansible webservers1 -m setup -a 'filter=ansible_all_ipv4_addresses'

常用 facts:

  • ansible_all_ipv4_addressesansible_default_ipv4
  • ansible_distribution/ansible_kernel
  • ansible_processor_cores/ansible_mem_total
  • ansible_python_version/ansible_pkg_mgr

Playbook 收集示例:

- hosts: alltasks:- name: 收集硬件信息setup:gather_subset: hardware- name: 收集网络信息setup:gather_subset: network

archive 打包

ansible webservers1 -m archive -a "path=/etc dest=/mnt/$(date +%F)-etc.tar.gz format=gz"

支持 tar/zip/gz/bz2 等格式,常用参数:path/dest/format/owner/mode

unarchive 解压

# 从控制端复制并解压到远端
ansible all -m unarchive -a "src=/root/arc.tar.gz dest=/root/" --become# 远端已有压缩包(不复制,只解压)
ansible all -m unarchive -a "src=/path/file.tar.gz dest=/path/ remote_src=yes"# 覆盖已有
ansible all -m unarchive -a "src=/root/a.tar.gz dest=/root/ extra_opts=--overwrite"

cron 定时任务

# 新增定时任务
ansible webservers -m cron -a 'name="deletefile" minute="53" hour="20" day="7" month="5" job="rm -rf /mnt/*"'
# 删除定时任务
ansible webservers -m cron -a "name='deletefile' state=absent"

更多 Playbook 写法:

- name: 每日 2 点备份cron:name: "daily backup"minute: "0"hour: "2"job: "/usr/local/bin/backup.sh"

get_url 下载文件

ansible webservers -m get_url -a "url=https://download.redis.io/releases/redis-7.0.10.tar.gz dest=/mnt force=yes"

常用参数:url/dest/backup/force/url_username/url_password

yum_repository 管理仓库源

# 创建本地源
ansible webserver -m yum_repository -a "name='Centos Base' file=base description='test' baseurl=file:///mnt/centos enabled=yes gpgcheck=no"# 配置阿里 EPEL 源
ansible webserver -m yum_repository -a "name=aliepel baseurl=https://mirrors.aliyun.com/epel/7/x86_64/ enabled=yes gpgcheck=yes gpgcakey=https://mirrors.aliyun.com/epel/RPM-GPG-KEY-EPEL-7 state=present file=AlicloudEpel description=alepel"# 删除仓库
ansible webserver -m yum_repository -a "file=base name='Centos Base' state=absent"

lineinfile 修改/插入行

关键参数:path/line/state/regexp/insertafter/create/backup

用法场景:批量改配置文件的某行,如 PermitRootLogin yes

debug 调试输出

# 输出字符串
ansible webservers -m debug -a "msg=hello,beijing"
# 输出变量(通过 -e 传入)
ansible webservers -m debug -a "var=a" -e "a=1234567"

Playbook 中常配合 register 把任务结果存变量后再 debug 打印。


四、Ansible Playbook 剧本

Playbook 基础与结构

  • Playbook 用 YAML 描述,适合多步骤批量操作。
  • 一个 Playbook = 若干个 Play;一个 Play = 在一组主机上按序执行多个任务(tasks)。

示例:

---
- name: first playgather_facts: false            # 跳过 facts 可加速hosts: webserversremote_user: root              # 建议改用 become 提权tasks:- name: test connectionping:- name: disable selinuxcommand: '/sbin/setenforce 0'ignore_errors: true- name: disable firewalldservice: name=firewalld state=stopped- name: install httpdyum: name=httpd state=latest- name: install configuration file for httpdcopy: src=/opt/httpd.conf dest=/etc/httpd/conf/httpd.confnotify: "restart httpd"          # 若变更则触发 handler- name: start httpd serviceservice: enabled=true name=httpd state=startedhandlers:- name: restart httpdservice: name=httpd state=restarted

提示(最佳实践):

  • 生产环境更推荐 become: yes 以普通用户登录再提权,少用 root 直连。
  • 文件路径/模板请用 templates/ + template 模块,便于变量化。

基础命令/输出颜色含义

ansible-playbook test.yml                     # 运行
ansible-playbook test.yml --syntax-check      # 语法检查
ansible-playbook test.yml --list-tasks        # 列出 tasks
ansible-playbook test.yml --list-hosts        # 列出主机
ansible-playbook test.yml --start-at-task 'install httpd'

颜色:绿色 success;黄色 changed(状态有变更);红色 failed(需排查)。

Tasks 示例

- hosts: webservers1user: roottasks:- name: create filefile: state=touch mode=0777 path=/tmp/playbook.txt- name: create dirfile: path=/mnt/dir12 state=directory

Handlers/Notify 触发器

  • 只有当某任务状态为 changed 时才触发对应 handler(并且在本 play 的所有普通任务结束后执行)。
- hosts: webservers1tasks:- name: test copycopy: src=/root/a.txt dest=/mntnotify: test handlershandlers:- name: test handlersshell: echo "abcd" >> /mnt/a.txt

常见用法:配置文件变更后“重启服务”。

循环/迭代(with_items/loop)

  • 字符串列表:
- hosts: websrvstasks:- name: install packagesyum:name: "{{ item }}"state: latestwith_items:- httpd- httpd-tools- php- php-mysql- php-mbstring- php-gd
  • loop(推荐新写法)创建用户/组:
- hosts: testtasks:- name: Create Groupsgroup:name: "{{ item }}"loop:- group1- group2- group3- name: Create Usersuser:name: "{{ item.user }}"group: "{{ item.group }}"uid: "{{ item.uid }}"loop:- { user: jack, group: group1, uid: 2001 }- { user: tom,  group: group2, uid: 2002 }- { user: alice,group: group3, uid: 2003 }
  • 批量安装/卸载:
- hosts: 192.168.157.129tasks:- name: install epelyum: name=epel-release state=latest- name: install packagesyum:name: "{{ item }}"state: latestloop:- httpd- mysql- nginx- redis

自定义变量与 vars_files

  • 优势:更清晰、可复用、一处修改全局生效。
  • 变量文件示例:/etc/ansible/vars/file.yml
src_path: /root/test/a.txt
dest_path: /opt/test/
  • Playbook 引用:
- hosts: ansible-web1vars_files:- /etc/ansible/vars/file.ymltasks:- name: create directoryfile: path={{ dest_path }} mode=0755 state=directory- name: copy filecopy: src={{ src_path }} dest={{ dest_path }}

分组与多 Play 示例(group 模块)

- hosts: webserver1tasks:- name: create a groupgroup: name=mygrp system=yes- name: create a useruser: name=tom group=mygrp system=yes- hosts: webserver2tasks:- name: install apacheyum: name=httpd state=latest- name: start httpd serviceservice: name=httpd state=started

gather_facts 与变量示例

- hosts: ansible-web1gather_facts: falsevars:user: jacksrc_path: /root/a.txtdest_path: /mnt/tasks:- name: create useruser: name={{ user }}- name: copy filecopy: src={{ src_path }} dest={{ dest_path }}

debug 调试 Playbook

- hosts: webservertasks:- name: create filefile: path=/mnt/debug.txt state=touchregister: create_file- name: 输出创建过程debug:msg: "{{ create_file }}"- hosts: webservervars:user1: jacktasks:- name: 打印变量debug:var: user1

条件判断 when

  • 作用:按条件决定 task 执行与否。常用比较:> >= < <= == !=
  1. 根据主机名条件创建文件:
- hosts: webservertasks:- name: create file when hostname is localhostfile: path=/mnt/test1.txt state=touchregister: create_filewhen: ansible_hostname == "localhost"
  1. 仅在 CentOS 上安装包:
- hosts: webservertasks:- name: install packageignore_errors: trueyum:name: "{{ item }}"state: latestloop:- nginx- rediswhen: ansible_distribution == "CentOS"
  1. 文件为空则写入内容:
- hosts: webservertasks:- name: ensure filefile: path=/opt/file.txt state=touch- name: check file contentshell: cat /opt/file.txtregister: check_file- name: insert hello when emptyshell: echo "hello" >> /opt/file.txtwhen: check_file.stdout == ""
  1. 服务未启动则启动(以 mysqld 为例):
- hosts: webservertasks:- name: check mysql statusshell: systemctl is-active mysqldregister: mysql_statusignore_errors: true- name: start mysql when inactiveservice: name=mysqld state=startedwhen: mysql_status.rc != 0

五、项目综合实战:Nginx + PHP Web 部署(CentOS 7)

本章节给出一套可直接运行的“多机 Web 部署”案例,涵盖目录规范、配置、角色拆分与一键部署。

1. 目标与架构

  • 目标:在一组 web 主机上部署 Nginx + PHP-FPM,发布一个简单 PHP 应用。
  • 架构:
    • 控制端:Ansible(CentOS 7)
    • 被控端:CentOS 7(组名 web
    • 组件:Nginx 作为前端,转发到 PHP-FPM。

2. 目录结构

建议项目结构(便于环境区分与复用):

ansible-project/
├─ ansible.cfg
├─ site.yml                  # 顶层编排
├─ inventories/
│  ├─ prod/
│  │  ├─ hosts.ini
│  │  └─ group_vars/
│  │     └─ web.yml
│  └─ dev/
│     └─ hosts.ini
└─ roles/├─ common/│  └─ tasks/main.yml├─ nginx/│  ├─ tasks/main.yml│  ├─ handlers/main.yml│  └─ templates/│     ├─ nginx.conf.j2│     └─ vhost.conf.j2├─ php/│  ├─ tasks/main.yml│  ├─ handlers/main.yml│  └─ templates/www.conf.j2└─ app/├─ tasks/main.yml└─ templates/index.php.j2

快速初始化(在控制端执行,示意):

mkdir -p ansible-project/inventories/{prod,dev}/group_vars
mkdir -p ansible-project/roles/{common,nginx,php,app}/{tasks,handlers,templates}
touch ansible-project/{ansible.cfg,site.yml}
touch ansible-project/inventories/prod/hosts.ini
touch ansible-project/inventories/prod/group_vars/web.yml

3. 基础配置与清单

ansible-project/ansible.cfg

[defaults]
inventory = inventories/prod/hosts.ini
forks = 10
host_key_checking = False
timeout = 30
deprecation_warnings = False
log_path = ./ansible.log

inventories/prod/hosts.ini

[web]
192.168.1.10 ansible_user=root
192.168.1.11 ansible_user=root[web:vars]
http_port=80
server_name=www.example.com
app_root=/var/www/app

inventories/prod/group_vars/web.yml(组变量):

http_port: 80
server_name: www.example.com
app_root: /var/www/app
php_fpm_listen: 127.0.0.1:9000
nginx_worker_processes: auto

4. 角色实现(common/nginx/php/app)

roles/common/tasks/main.yml:基础环境与常用工具。

---
- name: Ensure EPELyum: name=epel-release state=present- name: Install base toolsyum:name:- vim-enhanced- curl- unzip- gitstate: present- name: Set SELinux permissive (runtime)command: setenforce 0ignore_errors: true- name: Disable firewalld (demo)service: name=firewalld state=stopped enabled=noignore_errors: true

roles/nginx/tasks/main.yml

---
- name: Install nginxyum: name=nginx state=present- name: Deploy nginx.conftemplate: src=nginx.conf.j2 dest=/etc/nginx/nginx.confnotify: Restart nginx- name: Deploy vhosttemplate: src=vhost.conf.j2 dest=/etc/nginx/conf.d/app.confnotify: Restart nginx- name: Enable and start nginxservice: name=nginx state=started enabled=yes

roles/nginx/handlers/main.yml

---
- name: Restart nginxservice: name=nginx state=restarted

roles/nginx/templates/nginx.conf.j2(最小可用):

user nginx;
worker_processes {{ nginx_worker_processes | default('auto') }};
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
events { worker_connections 1024; }
http {include       /etc/nginx/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  /var/log/nginx/access.log  main;sendfile        on;keepalive_timeout  65;include /etc/nginx/conf.d/*.conf;
}

roles/nginx/templates/vhost.conf.j2

server {listen {{ http_port }};server_name {{ server_name }};root {{ app_root }};index index.php index.html;location / {try_files $uri $uri/ /index.php?$args;}location ~ \.php$ {include fastcgi_params;fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;fastcgi_pass {{ php_fpm_listen }};}
}

roles/php/tasks/main.yml

---
- name: Install PHP-FPM and extensionsyum:name:- php- php-fpm- php-cli- php-json- php-mbstring- php-xmlstate: present- name: Configure php-fpm pooltemplate: src=www.conf.j2 dest=/etc/php-fpm.d/www.confnotify: Restart php-fpm- name: Enable and start php-fpmservice: name=php-fpm state=started enabled=yes

roles/php/handlers/main.yml

---
- name: Restart php-fpmservice: name=php-fpm state=restarted

roles/php/templates/www.conf.j2(关键监听修改为变量):

[www]
user = nginx
group = nginx
listen = {{ php_fpm_listen }}
listen.owner = nginx
listen.group = nginx
pm = dynamic
pm.max_children = 5
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3

roles/app/tasks/main.yml:应用目录与首页。

---
- name: Ensure app root existsfile: path={{ app_root }} state=directory owner=nginx group=nginx mode=0755- name: Deploy index.phptemplate: src=index.php.j2 dest={{ app_root }}/index.php owner=nginx group=nginx mode=0644

roles/app/templates/index.php.j2

<?php
phpinfo();

5. site.yml 编排与运行

site.yml

---
- hosts: webbecome: yesroles:- common- php- nginx- app

运行:

cd ansible-project
ansible-playbook site.yml              # 使用默认 prod 清单
# 或指定清单
ansible-playbook -i inventories/prod/hosts.ini site.yml

6. 回滚与验证要点

  • 回滚建议:
    • 配置文件用 template + backup=yescopy backup=yes
    • 应用发布建议采用版本目录(releases/2025xxxx)+ current 符号链接模式;
    • 使用 unarchivecreates 防重复解压,或在任务中加 checksum 校验。
  • 验证:
    • 语法检查:nginx -t
    • 端口监听:ss -lntp | egrep ':80|:9000'
    • 服务状态:systemctl status nginx php-fpm
    • 页面验证:curl -I http://<web_ip>/ 或浏览器访问 http://server_name/

http://www.xdnf.cn/news/1350577.html

相关文章:

  • 强光干扰与密集场景下工服识别准确率↑89%!陌讯多模态融合算法在安全生产中的实战优化
  • 在Excel和WPS表格中快速插入多行或多列
  • 一个适用于 Word(Mac/Win 通用) 的 VBA 宏:把所有“上角标格式的 0‑9”以及 “Unicode 上角标数字 ⁰‑⁹” 批量删除。
  • PYTHON让繁琐的工作自动化-列表
  • 构建现代高并发服务器:从内核机制到架构实践
  • Win11 下卸载 Oracle11g
  • 青少年机器人技术(五级)等级考试试卷(2020年9月)
  • 基于Python对酷狗音乐排行榜数据分析可视化【源码+LW+部署】
  • 【Win】Motrix+Aria2浏览器下载加速
  • 深入解析Spring Boot自动配置原理:简化开发的魔法引擎
  • 在 Spring Boot 中配置和使用多个数据源
  • C++之list类的代码及其逻辑详解 (中)
  • 构建真正自动化知识工作的AI代理
  • 随着威胁的加剧,地方政府难以保卫关键基础设施
  • Java项目:基于SpringBoot和Vue的图书个性化推荐系统(源码+数据库+文档)
  • 以太坊智能合约地址派生方式:EOA、CREATE 和 CREATE2
  • C语言宏用法
  • Python 地理空间分析:核心库与学习路线图
  • ESP32应用——UDP组播/广播(ESP-IDF框架)
  • HarmonyOS 递归实战:文件夹文件统计案例解析
  • 配置npm国内源(包含主流npm镜像源地址)
  • 北极圈边缘生态研究:从数据采集到分析的全流程解析
  • 在github上通过dmca数字版权申诉侵权并删除侵权仓库
  • 【84页PPT】智慧方案某著名企业某集团协同OA整体解决方案(附下载方式)
  • IntelliJ IDEA 集成 ApiFox 操作与注解规范指南
  • C++ + Boost + MySQL 项目完整教程
  • mysql的mvcc
  • 如何用Redis作为消息队列
  • Science Robotics 通过人机交互强化学习进行精确而灵巧的机器人操作
  • Flink框架:算子链的介绍