基于 Ansible 与 Jinja2 模板的 LNMP 环境及 WordPress 自动化部署实践
使用JINJA2模板部署文件
示例 1:用模板部署 Web 服务器主页(显示主机名)
#1. 编写部署剧本(playbook.yml)[lyk@controller web 09:33:33]$ vim playbook.yml --- 2 - name: Enable intranet services3 hosts: node14 tasks: 5 - name: ensure latest version of httpd6 yum:7 name: httpd8 state: latest9 10 - name: test html page is installed11 template:12 src: index.html.ja13 dest: /var/www/html/index.html 14 15 - name: httpd enabled and running16 service:17 name: httpd18 enabled: true19 state: restarted20 ... #2. 编写 Jinja2 模板(index.html.ja)[lyk@controller web 09:42:20]$ vim index.html.ja1 Welcome to {{ ansible_fqdn }} #3. 执行部署并验证 lyk@controller web 09:44:02]$ ansible-playbook playbook.yml [lyk@controller web 09:44:16]$ curl http://node1/.Welcome to node1.lyk.cloud[lyk@controller web 09:44:59]$ curl http://node1/Welcome to node1.lyk.cloud[lyk@controller web 09:45:17]$ cat index.html.ja Welcome to {{ ansible_fqdn }}[lyk@controller web 09:46:38]$ curl http://node1/Welcome to node1.lyk.cloud[lyk@controller web 09:47:55]$ curl http://node2/Hello World From node2[lyk@controller web 09:47:58]$ curl http://node3/Hello World From node3[lyk@controller web 09:48:01]$ curl http://node4/Hello World From node4
示例 2:用模板配置 SSH 服务(自定义端口、权限等)
[lyk@controller web 09:51:20]$ vim playbook.yml 1 --- 2 - name: config sshd service3 hosts: node14 vars: 5 ssh_port: 10226 root_allowed: "yes"7 groups_allowed: wheel8 passwords_allowed: "yes"9 ansible_managed: "Ansible managed"10 tasks: 11 - name: config sshd service12 template:13 src: sshd_config.j214 dest: /root/sshd_config --剧本内容是告诉 Ansible 在node1上做三件事:--安装 / 更新 httpd(Apache Web 服务器);--用模板文件index.html.ja生成/var/www/html/index.html(网站主页);--启动并开机自启 httpd 服务。#2. 编写 Jinja2 模板(index.html.ja)[lyk@controller web 09:51:49]$ vim sshd_config.j21 # {{ ansible_managed }}2 # DO NOT MAKE LOCAL MODIFICATIONS TO THIS FILE AS THEY WILL BE LOST3 Port {{ ssh_port }}4 ListenAddress {{ ansible_facts['default_ipv4']['address'] }}5 6 HostKey /etc/ssh/ssh_host_rsa_key7 HostKey /etc/ssh/ssh_host_ecdsa_key8 HostKey /etc/ssh/ssh_host_ed25519_key9 SyslogFacility AUTHPRIV10 PermitRootLogin {{ root_allowed }}11 AllowGroups {{ groups_allowed }}12 13 AuthorizedKeysFile /etc/.rht_authorized_keys .ssh/authorized_keys14 PasswordAuthentication {{ passwords_allowed }} --模板里写的是Welcome to {{ ansible_fqdn }},其中{{ ansible_fqdn }}是 ---Ansible 的内置变量,代表 “受管主机的完整主机名”(比如node1.lyk.cloud)。--作用:用模板生成的主页会自动替换变量,显示目标主机自己的完整主机名。[lyk@controller web 09:51:04]$ ansible-playbook playbook.yml
Jinja2 模板语法
for 语句
[lyk@controller web 10:34:01]$ vim playbook.yml 1 --- 2 - name: test template 3 hosts: node1 4 vars: 5 users: 6 - tom 7 - jack 8 - Snoopy 9 - lucky 10 tasks: 11 - name: test template 12 template: 13 src: testfile.j2 14 dest: /tmp/testfile 15 ... [lyk@controller web 10:48:50]$ vim testfile.j21 {% for user in users %} 2 username is {{ user }}3 {% endfor %}[lyk@controller web 11:01:37]$ ansible-playbook playbook.yml #node1查看[lyk@node1 ~ 09:05:58]$ cat /tmp/testfileusername is tomusername is jackusername is Snoopyusername is lucky
基于 Ansible 的 LNMP 环境自动化部署与 WordPress 搭建
#1. 准备工作:复制和清理目录lyk@controller ~ 13:47:02]$ cp -r web lnmp[lyk@controller ~ 13:52:05]$ cd lnmp/[lyk@controller lnmp 13:52:33]$ rm -fr *#2. 复制核心配置文件[lyk@controller lnmp 13:52:50]$ cp ../web/ansible.cfg .[lyk@controller lnmp 13:53:17]$ cp ../web/inventory .#3. 编辑主机清单(inventory)[lyk@controller lnmp 13:53:44]$ vim inventory 1 [lnmps]2 lnmp ansible_host=node13 4 [controllers]5 controller6 7 [dev]8 node19 10 [test]11 node212 13 [prod]14 node315 node4 #4. 编写部署剧本(deploy_lnmp.yml) [lyk@controller lnmp 13:55:16]$ vim deploy_lnmp.yml---- name: deploy mariadbhosts: lnmptasks:# 安装数据库- name: install mariadb-serveryum:name: - mariadb-server- python2-PyMySQLstate: present# 启动服务- name: enable and start mariadbservice:name: mariadbenabled: yesstate: started# 设置 root 密码- name: set root@localhost passwordshell: mysqladmin password {{ mysql_root_password }}ignore_errors: yes- name: set root passwordmysql_user:name: rootpassword: "{{ mysql_root_password }}"host: "{{ item }}"state: presentlogin_user: rootlogin_password: "{{ mysql_root_password }}"with_items:- "{{ ansible_fqdn }}"- 127.0.0.1- ::1# 删除匿名用户- name: delete user anonymousmysql_user:name: ""host_all: yesstate: absentlogin_user: rootlogin_password: "{{ mysql_root_password }}"#login_unix_socket: /var/lib/mysql/mysql.sock# 删除测试数据库- name: delete database testmysql_db:name: teststate: absentlogin_user: rootlogin_password: "{{ mysql_root_password }}"- name: prepare db for webapphosts: lnmptasks:# 创建新用户- name: create user {{ user }}mysql_user:name: "{{ app_user }}"password: "{{ app_password }}"host: "{{ app_host }}"priv: "{{ app_priv }}"state: presentlogin_user: rootlogin_password: "{{ mysql_root_password }}"# 创建新库- name: create database db_namemysql_db:name: "{{ db_name }}"state: presentlogin_user: rootlogin_password: "{{ mysql_root_password }}"- name: deploy web serverhosts: lnmptasks:- name: install nginxyum:name: nginxstate: present# 启动服务- name: enable and start nginxservice:name: nginxenabled: yesstate: started- name: prepare test file for web servercopy:content: hello world from nginxdest: /usr/share/nginx/html/index.html- name: phphosts: lnmptasks:- name: install phpyum:name: php,php-fpm,php-mysqlndstate: present- name: modify running user for phplineinfile:path: /etc/php-fpm.d/www.confregexp: "{{ item}} = "line: "{{ item }} = nginx"loop:- user- group# 启动服务- name: enable and start php-fpm.serviceservice:name: php-fpmenabled: yesstate: restarted- name: config php for nginxcopy:src: php.confdest: /etc/nginx/default.d/php.conf- name: restart nginxservice:name: nginxstate: restarted- name: deploy web apphosts: lnmpvars:blog_vhost: blog.lyk.cloudtasks:- name: prepare vhost for wordpresstemplate:src: vhost-wordpress.conf.j2dest: /etc/nginx/conf.d/vhost-wordpress.conf- name: create /usr/share/nginx/html/{{ blog_vhost }}file:path: /usr/share/nginx/html/{{ blog_vhost }}state: directory- name: Unarchive a wordpress file unarchive:src: wordpress-4.9.4-zh_CN.zipdest: /usr/share/nginx/html/{{ blog_vhost }}/owner: nginxgroup: nginx- name: restart nginxservice:name: nginxstate: restarted--部署 MariaDB(数据库):安装数据库软件、启动服务、设置 root 密码、删除默认的匿名用户和测试库(安全加固)。--准备数据库(给 Web 应用用):创建一个专用的数据库用户(比如wordpress)和数据库(比如webapp),让 Web 程序能连接数据库。--部署 Nginx(Web 服务器):安装 Nginx、启动服务,先放一个简单的 “hello world” 页面测试。--部署 PHP:安装 PHP 及相关组件(处理动态网页),配置 PHP 和 Nginx 配合工作(让 Nginx 遇到.php文件时交给 PHP 处理)。--部署 Web 应用(WordPress):配置 Nginx 虚拟主机(让blog.lyk.cloud这个域名指向 WordPress)、创建网站目录、解压 WordPress 程序包并设置权限。# 5. 创建变量文件(存密码和配置) [lyk@controller lnmp 13:58:00]$ mkdir host_vars[lyk@controller lnmp 13:58:32]$ mkdir host_vars/lnmp[lyk@controller lnmp 13:58:52]$ vim hostvars/lnmp/vaults.yml1 mysql_root_password: lyk@1232 app_user: wordpress 3 app_password: lyk@1234 app_host: '%' 5 app_priv: '*.*:ALL'--里面存的是 “敏感变量”(需要加密的信息):--mysql_root_password: lyk@123:数据库 root 用户的密码。--app_user: wordpress:给 Web 应用用的数据库用户名。--app_password: lyk@123:Web 应用用户的密码。--这些信息不能明文存,所以后面会加密。#db_name: webapp:给 Web 应用用的数据库名字 [lyk@controller lnmp 14:05:58]$ vim hostvars/lnmp/vars.yml1 db_name: webapp #6. 配置 PHP 和 Nginx 配合 [lyk@controller lnmp 14:07:41]$ vim php.conf 1 location ~ \.php$ {2 try_files $uri =404;3 fastcgi_pass 127.0.0.1:9000;4 fastcgi_index index.php;5 fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;6 include fastcgi_params;7 } #拖入wordpress-4.9.4-zh_CN.zip[lyk@controller lnmp 14:10:49]$ rz -Erz waiting to receive.[lyk@controller lnmp 14:10:58]$ lsansible.cfg hostvars php.confdeploy_lnmp.yml inventory wordpress-4.9.4-zh_CN.zip[lyk@controller lnmp 14:11:41]$ unzip wordpress-4.9.4-zh_CN.zip [lyk@controller lnmp 14:12:02]$ lsansible.cfg hostvars php.conf wordpress-4.9.4-zh_CN.zipdeploy_lnmp.yml inventory wordpress#7. 准备 WordPress 程序[lyk@controller lnmp 14:12:21]$ ls wordpressindex.php wp-blog-header.php wp-includes wp-settings.phplicense.txt wp-comments-post.php wp-links-opml.php wp-signup.phpreadme.html wp-config-sample.php wp-load.php wp-trackback.phpwp-activate.php wp-content wp-login.php xmlrpc.phpwp-admin wp-cron.php wp-mail.php#8.到nginx里面复制模板到vhost-wordpress.conf.j2, 配置 Nginx 虚拟主机(域名对应网站)[lyk@controller web 11:00:26]$ sudo yum install -y nginx[lyk@controller web 14:15:30]$ vim /etc/nginx/nginx.conf[lyk@controller lnmp 14:12:39]$ vim vhost-wordpress.conf.j21 server {2 listen 80;3 server_name {{ blog_vhost }};4 root /usr/share/nginx/html/{{ blog_vhost }}/wordpress;5 index index.php;6 7 # Load configuration files for the default server block.8 include /etc/nginx/default.d/*.conf;9 10 # log file11 access_log /var/log/nginx/access-{{ blog_vhost }}.log;12 error_log /var/log/nginx/error-{{ blog_vhost }}.log;13 } #9. 加密敏感信息(保护密码)[lyk@controller lnmp 14:19:13]$ ansible-vault encrypt hostvars/lnmp/vaults.ymlNew Vault password: ##lyk@123Confirm New Vault password: ##lyk@123Encryption successful[lyk@controller lnmp 14:21:48]$ echo lyk@123 > secret.txt#编辑 Ansible 配置文件,添加vault_password_file=./secret.txt,告诉 Ansible:“解密vaults.yml时,自动从secret.txt读密码”(不用手动输入)[lyk@controller lnmp 14:22:30]$ vim ansible.cfg 1 [defaults]2 remote_user = lyk3 inventory = ./inventory4 #roles_path =./roles5 #collections_paths =./collections 6 vault_password_file=./secret.txt7 8 [privilege_escalation]9 become = True10 become_user = root11 become_method = sudo12 become_ask_pass = False#测试解密查看vaults.yml,确认加密正常(能看到解密后的密码)[lyk@controller lnmp 14:27:07]$ ansible-vault view hostvars/lnmp/vaults.yml mysql_root_password: lyk@123app_user: wordpressapp_password: lyk@123app_host: '%'app_priv: '*.*:ALL'[lyk@controller lnmp 14:28:55]$ mv hostvars/ host_vars#10. 目标主机(node1)的清理工作[lyk@node1 ~ 14:31:56]$ systemctl status httpd● httpd.service - The Apache HTTP ServerLoaded: loaded (/usr/lib/systemd/system/httpd.service; enabled; vendor preset: disabled)Active: active (running) since 一 2025-08-18 09:44:16 CST; 4h 47min ago ##running导致nginx不能使用Docs: man:httpd(8)#关闭[lyk@node1 ~ 14:33:41]$ sudo systemctl disable httpd --now#清除之前数据库密码[root@node1 ~ 15:41:29]# systemctl stop mariadb[root@node1 ~ 15:41:37]# rm -fr /var/lib/mysql/*[lyk@controller lnmp 14:38:27]$ ansible-playbook deploy_lnmp.yml
登录网页
# C:\Windows\System32\drivers\etc添加10.1.8.11 blog.lyk.cloud#浏览器输入blog.lyk.cloud