机器环境管理

对于机器的环境管理,已经痛苦很长时间了,每次机器创建之后,需要先部署基础环境,比如 Java、tomcat 等,然后再发布应用程序。对于这个问题,我之前一直想用 Docker 解决,但是事实上 Docker 也不能解决所有的问题,比如 Hadoop 并不适合 Docker,对于 Hadoop 这种适合部署在机器上的组件还需要手动维护基础环境。

作为一个有追求的不断提高效率的人,我现在终于决定要解决这个问题了,也就是机器的环境管理问题。

事实上,机器分为 物理机 和 虚拟机,对于大部分类 Web 程序我们使用虚拟机,对于 Hadoop、Mysql 等资源消耗型程序我们使用物理机,而且物理机和虚拟机基本没有「混布」,这是前提,如果混布,管理起来会麻烦很多(需要分目录来管理,不能共用)。

 

因为一个服务的环境是一样的,所以我们基于服务树来统一管理服务的环境,思路很简单:

1. 把 服务节点 和 Puppet class 做一个关联,即表示服务节点下的所有机器都使用此 Puppet class 来配置基础环境。

2. Puppet 有多个 class,class 之间的继承等关联关系通过 Puppet 配置文件来维护;

3. Puppet class 需要暴露出来一个 class 的列表来供做关联的时候做选择,这个列表可以放在 Puppet 配置中的一个文件里,文件对外提供 HTTP 下载(然后再封装成 API)。

那么,当机器来请求 Puppet 获取配置的时候,怎么返回呢?

参考 这篇文章,我们使用 Puppet 的 ENC 功能,写一个自定义脚本,传入机器名,返回包含 class 的 yaml 格式文本。脚本的流程:

1. 根据机器名获取机器属于哪个(些)服务节点(基于服务树 API);

2. 根据服务节点获取 Puppet class;

3. 拼成 yaml 格式文本并打印。

如果属于多个服务节点,而且服务节点的 Puppet class 不一样,此时可以使用 default class (只配置系统基础环境,不配置应用基础环境)。

 

但是,还有一个问题,如何在机器创建之后立即配置环境?

现状是:

1. 机器安装好之后会立即执行 Puppet;

2. Puppet 执行之后会自动安装资产系统 agent,agent 把机器上报到资产系统,表示此机器安装完成;

3. 然后调用 API 把机器关联到安装机器时指定的服务节点。

像上面讲的,Puppet 配置(应用)基础环境需要知道是哪个服务节点,而第 1 步的时候不知道是哪个服务节点。

这里抛出一个修改 ENC 脚本的方法:

1. ENC 调用服务树 API,获取机器绑定的服务节点;

2. 如果找不到节点,那么继续调用装机系统 API,获取服务节点。

这种方法只有「正在装」的机器才会调用装机系统 API,增加的调用不多,所以能接受。

 

Puppet file 指令删除目标目录中的不在源目录中的文件

file {‘/home/op/open-falcon-agent/plugin’:
path => ‘/home/op/open-falcon-agent/plugin/’,
source => ‘puppet:///modules/sre-scripts/’,
recurse => true,
ignore => ‘.git’,
group => root,
owner => root,
mode => 755,
purge => true,
force => true,
require => Package[‘open-faclon-agent’]
}

这段配置,把 puppet:///modules/sre-scripts/ 中的目录和文件同步到 /home/op/open-falcon-agent/plugin,如果想把 /home/op/open-falcon-agent/plugin 中不在 puppet:///modules/sre-scripts/ 中的文件和目录删除掉,可以使用:

purge => true,
force => true,

purge => 默认会删除文件,不会删除目录,再配合使用 force => true,可以把不存在的目录删掉。

2F7828D7-1698-4746-A268-0D7C3965B027

 

参考:

https://docs.puppet.com/puppet/latest/reference/type.html

 

搭建 Puppet dashboard 来监测 Puppet 更新失败的问题

最近花了几天搞了一下 Puppet 更新失败的问题,总结了一下遇到的问题,问题还挺多的,这就是开发有登陆机器权限的恶果,问题列表:

1.crontab 任务被注释(我们使用 crontab 来更新 Puppet);

2.证书问题,基本上都是证书已经存在,证书申请失败,此时需要到 Puppet ca 删掉原有证书,并清空本机证书,重新申请;

这种情况 Puppet Master 是拿不到更新信息的,所以 Puppet Dashboard 看不到这种机器。

一般是由改主机名引起,可以通过修改改名脚本彻底解决:

1). 改名之前去 Puppet ca 删除原主机名的证书;

2). 删除本机的证书文件;

3). 查看 Puppet ca 中是否已经存在新主机名的证书;

4). 如果存在,删除 Puppet ca 中的新主机名证书;

5). 真正改名。

3.Puppet 依赖的 ruby 环境被损坏;

4.升级 Python 导致 yum 不可用;

5.普通用户进程数达到上限导致 lighttpd(Nginx 七层检测用) 起不来;

6.升级 Python 导致 supervisor 启动不了;

7.一些自定义 rpm 包不支持 Centos7,启动失败;

8.mysql-libs 和 Percona-Server-server 冲突;

解决方法:
安装 Percona-Server-shared-compat 代替 mysql-libs 。

9.Puppet 忽略此节点,返回400;

通过修改 puppet_node_classifer.py 解决,忽略的节点也返回执行 Puppet 主任务的 crontab配置。

10.机器死机。

 

 

问题多多,所以安装 Puppet Dashboard 来观察哪些机器更新失败。

1.安装:

yum install rubygem-rake ruby-mysql mysql-server puppet-dashboard

2.修改 /etc/my.conf,在 [mysqld] 内加入
max_allowed_packet = 32M

然后 在 [mysqld] 和 [client ]内加入
defalut-character-set = utf8

3.创建mysql数据库和用户

create database dashboard;
grant all on dashboard.* to puppet@’10.%’ identified by ‘puppetdashboard’;
flush privileges;

4.修改 /usr/share/puppet-dashboard/config/database.yml

production:
database: dashboard
username: puppet
password: dashboard
encoding: utf8
adapter: mysql

5.导入表结构

cd /usr/share/puppet-dashboard
rake gems:refresh_specs
rake RAILS_ENV=production db:migrate

6.测试 puppet-dashboard 能否工作,端口起在 3000

/usr/share/puppet-dashboard/script/server -e production

7.启动

/usr/share/puppet-dashboard/script/server -e production -d
env RAILS_ENV=production /usr/share/puppet-dashboard/script/delayed_job -p dashboard -n 4 -m start
/etc/init.d/mysql.server start

8.访问。

通过 http://puppetdashboard:3000

 

额外要注意的几点:

1.Puppet client 更新 Puppet 的时候需要指定 report 参数,比如:
/usr/bin/puppet agent –onetime –no-daemonize –server=puppetlb.corp.nosa.me –ca_server=puppetca.corp.nosa.me report

2.要在 Puppet master 的 [main] 下面增加两行:
reports = http,store
reporturl = http://puppetdashboard:3000/reports/upload

3.默认是 UTC 时区,修改成北京时间,编辑文件 /usr/share/puppet-dashboard/config/settings.yml,修改 time_zone:

time_zone: ‘Beijing’

4.dashboard 的数据库文件增加很快,如果不清理,很快就会占满硬盘,最好每天清理一次,清理脚本可如下(保留一天):

cd /usr/share/puppet-dashboard
env RAILS_ENV=production rake reports:prune upto=1 unit=day
env rake RAILS_ENV=production db:raw:optimize

 

 

最后,要通过 api 获取更新失败的机器列表 和 通过 api 查询、删除 证书 可以参考 这里,查询和删除证书要认证,如果怕麻烦 可以修改 Puppet ca 的 /etc/puppet/auth.conf ,增加 allow *,只是不太安全。

 

如何动态获取 Puppet node 指令定义的机器列表

我的需求是这样的,比如我这 Puppet 配置文件里面定义下面的配置来配置 NTP Server :

node "ntp0.hy01.nosa.me", "ntp2.hy01.nosa.me" {
    class { ‘::ntp':
        servers => [
            ‘0.pool.ntp.org’,
            ‘1.pool.ntp.org’,
            ‘stdtime.gov.hk’
        ],
        }
}

ntp0.hy01.nosa.me 和 ntp1.hy01.nosa.me 是写死的,如果机器变化需要手动修改,很麻烦,所以想动态获取。


Puppet 里面有一个功能叫做 ENC(全称是 External Node Classifiers ,网址 ) 可以变相实现这个功能。

先说下怎么用 ENC,需要在 puppet.conf 的 [master] 里面 加上类似 :

node_terminus = exec
external_nodes = /etc/puppet/puppet_node_classifer.py

然后 /etc/puppet/puppet_node_classifer.py (路径可改) 要有执行权限,这个脚本需要有一个参数,就是 「来请求 Puppet 的 主机名(FNDQ)」,然后这个脚本的输出需要是 yaml 格式,比如

$ ./puppet_node_classifer.py ntp0.hy01.nosa.me
—
classes:
– ntp_server

那么,当 ntp0.hy01.nosa.me 来请求 Puppet 的时候 Puppet 会执行 ./puppet_node_classifer.py ntp0.hy01.nosa.me,Puppet 拿到 yaml 格式的配置之后 做一个转换,上面的 yaml 配置相当于如下:

node "ntp0.hy01.nosa.me"  {
    include ntp_server
}

此时 ntp_server 这个 class 可以这么定义 (我是定义在 /etc/puppet/manifests/site.pp 文件中):

class ntp_server {
    class { ‘::ntp':
        servers => [
            ‘0.pool.ntp.org’,
            ‘1.pool.ntp.org’,
            ‘stdtime.gov.hk’
        ],
    }
}

puppet_node_classifer.py 我是这么实现的,先从 「服务数节点」去抓所有 NTP server 的服务器列表,如果 「此台机器」在列表里,那么就返回相应的 yaml 配置。