Jinja是一种基于python的模板引擎,在SLS文件里可以直接使用jinja模板来做一些操作。
通过jinja模板可以为不同服务器定义各自的变量。
两种分隔符: {% ... %}
和 { { ... }}
,前者用于执行诸如 for 循环 或赋值的语句,后者把表达式的结果打印到模板上(引用)。
Jinja最基本的用法是使用控制结构包装条件:
[root@server1 salt]# vim test.sls
[root@server1 salt]# cat test.sls
/mnt/testfile:
file.append:
{
% if grains['fqdn'] == 'server2' %}
- text: server2
{
% elif grains['fqdn'] == 'server3' %}
- text: server3
{
% endif %}
以上文件的内容表示在server2和server3创建文件/mnt/testfile
,并将不同的内容添加进入文件。
推送:
[root@server1 salt]# salt '*' state.sls test
在server2查看:
[root@server2 ~]# cd /mnt/
[root@server2 mnt]# cat testfile
server2
在server3查看:
[root@server3 ~]# cd /mnt/
[root@server3 mnt]# cat testfile
server3
Jinja在普通文件的使用:
[root@server1 salt]# cd apache/
[root@server1 apache]# vim init.sls
[root@server1 apache]# cat init.sls
apache:
pkg.installed:
- pkgs:
- {
{
pillar['webserver'] }}
service.running:
- name: httpd
- reload: true
- enable: true
- watch:
- file: /etc/httpd/conf/httpd.conf
/etc/httpd/conf/httpd.conf:
file.managed:
- source: salt://apache/httpd.conf
- template: jinja
- context:
bind: 172.25.63.3
port: 80
其中:
- template: jinja #启用jinja模板
- context:
bind: 172.25.63.3 #定义变量
port: 80
表示启用jinja模板和定义变量,接下来在配置文件中调用变量:
[root@server1 apache]# vim httpd.conf
[root@server1 apache]# cat -n httpd.conf | grep 42
42 Listen {
{
bind }}:{
{
port }}
推送(由于ip已经设置,故推送给server3):
[root@server1 apache]# salt server3 state.sls apache
推送成功,在server3查看:
[root@server3 ~]# netstat -antlpe | grep 80
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 0 34667 3047/nginx: master
查看配置文件:
[root@server3 ~]# cat -n /etc/httpd/conf/httpd.conf | grep 42
42 Listen 172.25.63.3:80
从配置文件可以看出变量成功调用。
但是这种方式在主机数量增多后就不太合适,我们可以结合grains和pillar来进行调用:
[root@server1 apache]# vim init.sls
[root@server1 apache]# cat init.sls
apache:
pkg.installed:
- pkgs:
- {
{
pillar['webserver'] }}
service.running:
- name: httpd
- reload: true
- enable: true
- watch:
- file: /etc/httpd/conf/httpd.conf
/etc/httpd/conf/httpd.conf:
file.managed:
- source: salt://apache/httpd.conf
- template: jinja
- context:
bind: {
{
grains['ipv4'] }}
port: 80
但是这种方式调用时,grains['ipv4']
是个列表:
[root@server1 apache]# salt server3 grains.item ipv4
server3:
----------
ipv4:
- 127.0.0.1
- 172.25.63.3
在推送时就会有问题:
[root@server1 apache]# salt server3 state.sls apache
可以看出apache并不支持列表的形式,因此我们可以使用切片(与python的切片方法相同):
[root@server1 apache]# vim init.sls
[root@server1 apache]# cat init.sls
apache:
pkg.installed:
- pkgs:
- {
{
pillar['webserver'] }}
service.running:
- name: httpd
- reload: true
- enable: true
- watch:
- file: /etc/httpd/conf/httpd.conf
/etc/httpd/conf/httpd.conf:
file.managed:
- source: salt://apache/httpd.conf
- template: jinja
- context:
bind: {
{
grains['ipv4'][-1] }}
port: 80
再次推送:
[root@server1 apache]# salt server3 state.sls apache
可以看出推送成功。
我们也可以将port变量调用pillar的值:
[root@server1 apache]# vim init.sls
[root@server1 apache]# cat init.sls
apache:
pkg.installed:
- pkgs:
- {
{
pillar['webserver'] }}
service.running:
- name: httpd
- reload: true
- enable: true
- watch:
- file: /etc/httpd/conf/httpd.conf
/etc/httpd/conf/httpd.conf:
file.managed:
- source: salt://apache/httpd.conf
- template: jinja
- context:
bind: {
{
grains['ipv4'][-1] }}
port: {
{
pillar['port'] }}
推送:
[root@server1 apache]# salt server3 state.sls apache
成功推送。
此时更改pillar的信息:
[root@server1 pillar]# vim web.sls
[root@server1 pillar]# cat web.sls
{
% if grains['fqdn'] == 'server3' %}
webserver: httpd
port: 8080
{
% elif grains['fqdn'] == 'server2' %}
webserver: nginx
port: 80
{
% endif %}
将server3的端口改为8080,推送:
[root@server1 apache]# salt server3 state.sls apache
在server3查看端口:
[root@server3 ~]# netstat -antlpe | grep 8080
tcp 0 0 172.25.63.3:8080 0.0.0.0:* LISTEN 0 45425 3749/httpd
可以看出已经更改为8080.
当然也可以直接在配置文件中调用grains或者pillar:
[root@server1 apache]# vim init.sls
[root@server1 apache]# cat init.sls
apache:
pkg.installed:
- pkgs:
- {
{
pillar['webserver'] }}
service.running:
- name: httpd
- reload: true
- enable: true
- watch:
- file: /etc/httpd/conf/httpd.conf
/etc/httpd/conf/httpd.conf:
file.managed:
- source: salt://apache/httpd.conf
- template: jinja #注意需要启用jinja模板
[root@server1 apache]# vim httpd.conf
[root@server1 apache]# cat -n httpd.conf | grep 42
42 Listen {
{
grains['ipv4'][-1] }}:{
{
pillar['port'] }}
然后推送:
[root@server1 apache]# salt server3 state.sls apache
可以看出推送成功。
第三种方式为import方式,可在state文件之间共享:
定义变量文件:
[root@server1 salt]# vim lib.sls
[root@server1 salt]# cat lib.sls
{
% set port = 80 %}
导入模板文件:
[root@server1 salt]# cd apache/
[root@server1 apache]# vim httpd.conf
[root@server1 apache]# head -1 httpd.conf
{
% from 'lib.sls' import port %}
调用变量:
[root@server1 apache]# cat -n httpd.conf | grep 43
43 Listen {
{
grains['ipv4'][-1] }}:{
{
port }}
推送:
[root@server1 apache]# salt server3 state.sls apache
在server3查看可以看出配置已经生效:
[root@server3 ~]# netstat -antlpe | grep httpd
tcp 0 0 172.25.63.3:80 0.0.0.0:* LISTEN 0 45983 3749/httpd
但是我们先在考虑一个问题,如果我们不仅在init文件中定义了变量port,还用import方式定义了变量,当调用的时候哪个优先级高呢,通过实验看下结果:
在init文件中定义变量port为8080(这里调用的pillar,server3的pillar port为8080):
[root@server1 apache]# vim init.sls
[root@server1 apache]# cat init.sls
apache:
pkg.installed:
- pkgs:
- {
{
pillar['webserver'] }}
service.running:
- name: httpd
- reload: true
- enable: true
- watch:
- file: /etc/httpd/conf/httpd.conf
/etc/httpd/conf/httpd.conf:
file.managed:
- source: salt://apache/httpd.conf
- template: jinja
- context:
# bind: {
{ grains['ipv4'][-1] }}
port: {
{
pillar['port'] }}
import的方式我们上面已经设置过了,因此我们直接推送查看结果:
[root@server1 apache]# salt server3 state.sls apache
server3查看:
[root@server3 ~]# netstat -antlpe | grep httpd
tcp 0 0 172.25.63.3:80 0.0.0.0:* LISTEN 0 45983 3749/httpd
可以看出通过import的方式导入的变量优先级高于在init文件中定义的变量,原因是在运行的时候最后读取的是import方式导入的变量。
注意:一般习惯将变量都定义在init文件中,然后在其他文件中引用即可。
我们这里准备将server2设置为master节点,server3为backup节点,vip为172.25.63.100
。
首先编辑init文件在节点安装keepalived:
[root@server1 salt]# mkdir keepalived
[root@server1 salt]# cd keepalived/
[root@server1 keepalived]# vim init.sls
[root@server1 keepalived]# cat init.sls
install-kp:
pkg.installed:
- name: keepalived
推送测试:
[root@server1 keepalived]# salt '*' state.sls keepalived
安装成功。
继续编辑init文件,设置配置文件以及服务:
[root@server1 keepalived]# vim init.sls
[root@server1 keepalived]# cat init.sls
install-kp:
pkg.installed:
- name: keepalived
file.managed:
- name: /etc/keepalived/keepalived.conf
- source: salt://keepalived/keepalived.conf
service.running:
- name: keepalived
- reload: true
- watch:
- file: install-kp
复制配置文件:
[root@server1 keepalived]# scp server2:/etc/keepalived/keepalived.conf .
[root@server1 keepalived]# ls
init.sls keepalived.conf
编辑配置文件:
[root@server1 keepalived]# vim keepalived.conf
[root@server1 keepalived]# cat keepalived.conf
! Configuration File for keepalived
global_defs {
notification_email {
root@localhost
}
notification_email_from keepalived@localhost
smtp_server 127.0.0.1
smtp_connect_timeout 30
router_id LVS_DEVEL
}
vrrp_instance VI_1 {
state MASTER
interface eth0
virtual_router_id 51
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
172.25.63.100
}
}
可以看出配置文件中的角色为master,优先级为100,vip为172.25.63.100。
推送给server2测试:
[root@server1 keepalived]# salt server2 state.sls keepalived
推送成功。
在server2查看日志:
[root@server2 mnt]# tail -20 /var/log/messages
可以看出是master的身份,查看ip:
可以看出已经获得了虚拟ip。
server2部署成功,但是现在有一个问题,server3(backup节点)的配置文件和server2不同,不能直接推送,我们可以结合jinja模板与pillar实现不同主机的配置文件不同。
更改配置文件:
[root@server1 keepalived]# vim keepalived.conf
[root@server1 keepalived]# cat keepalived.conf
! Configuration File for keepalived
global_defs {
notification_email {
root@localhost
}
notification_email_from keepalived@localhost
smtp_server 127.0.0.1
smtp_connect_timeout 30
router_id LVS_DEVEL
}
vrrp_instance VI_1 {
state {
{
STATE }}
interface eth0
virtual_router_id 51
priority {
{
PRI }}
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
{
{
VIP }}
}
}
其中STATE、PRI、VIP为变量,接下来我们就需要定义pillar变量:
[root@server1 keepalived]# cd /srv/pillar/
[root@server1 pillar]# vim web.sls
[root@server1 pillar]# cat web.sls
{
% if grains['fqdn'] == 'server2' %}
kpstate: MASTER
kppri: 100
{
% elif grains['fqdn'] == 'server3' %}
kpstate: BACKUP
kppri: 50
{
% endif %}
在init文件中将pillar变量赋值给配置文件中的三个变量:
[root@server1 pillar]# cd -
/srv/salt/keepalived
[root@server1 keepalived]# vim init.sls
[root@server1 keepalived]# cat init.sls
install-kp:
pkg.installed:
- name: keepalived
file.managed:
- name: /etc/keepalived/keepalived.conf
- source: salt://keepalived/keepalived.conf
- template: jinja
- context:
STATE: {
{
pillar['kpstate'] }} #将pillar变量赋值给配置文件中的三个变量
PRI: {
{
pillar['kppri'] }}
VIP: {
{
pillar['vip'] }}
service.running:
- name: keepalived
- reload: true
- watch:
- file: install-kp
现在可以直接推送给两个节点:
[root@server1 keepalived]# salt '*' state.sls keepalived
配置成功。
在server2查看:
[root@server2 mnt]# tail -20 /var/log/messages
.......
May 18 23:34:05 server2 Keepalived_vrrp[3688]: VRRP_Instance(VI_1) Transition to MASTER STATE
可以看出已经获得vip:
[root@server2 mnt]# ip addr
......
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 52:54:00:be:bf:d2 brd ff:ff:ff:ff:ff:ff
inet 172.25.63.2/24 brd 172.25.63.255 scope global eth0
valid_lft forever preferred_lft forever
inet 172.25.63.100/32 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::5054:ff:febe:bfd2/64 scope link
valid_lft forever preferred_lft forever
在server3查看:
[root@server3 ~]# tail -20 /var/log/messages
......
May 18 23:34:04 server3 Keepalived_vrrp[4100]: VRRP_Instance(VI_1) Entering BACKUP STATE
May 18 23:34:04 server3 Keepalived_vrrp[4100]: VRRP_Instance(VI_1) removing protocol VIPs.
可以看出已经部署完成。
接下来进行测试:
关闭server2的keepalived:
[root@server2 mnt]# systemctl stop keepalived
查看server3已经自动切换成了master节点并且得到了vip:
此时在server1再次进行推送:
[root@server1 keepalived]# salt '*' state.sls keepalived
推送后由于server2的服务会被启动,且优先级(100)高于serve3(50),因此server2又会变成master节点:
高可用集群成功部署。
也可以不使用pillar,直接将变量定义在init文件中,比如下面这种写法和上面的效果是相同的:
[root@server1 keepalived]# vim init.sls
[root@server1 keepalived]#
[root@server1 keepalived]# cat init.sls
install-kp:
pkg.installed:
- name: keepalived
file.managed:
- name: /etc/keepalived/keepalived.conf
- source: salt://keepalived/keepalived.conf
- template: jinja
- context:
{
% if grains['fqdn'] == 'server2' %}
STATE: MASTER
PRI: 100
VIP: 172.25.63.100
{
% elif grains['fqdn'] == 'server3' %}
STATE: BACKUP
PRI: 50
VIP: 172.25.63.100
{
% endif %}
service.running:
- name: keepalived
- reload: true
- watch:
- file: install-kp
当节点数量多时还是推荐结合pillar的方法。