在 Ubuntu 12.04 上安装和配置邮件服务

postfix

前段时间把一台 FreeBSD 邮件服务器移到了 Ubuntu 虚拟机,又痛苦的配置了一次邮件服务器,配置完后再写一遍 Puppet 代码,把整个配置过程代码化,然后再重建一次虚拟机测试和应用 Puppet 代码,每次看到满屏的自动配置过程都会惊讶 Puppet 的魔力

邮件服务器配置之所以麻烦是因为需要了解很多东西,牵涉到域名服务 DNS/Bind,Web 收发邮件 Apache/PHP/MySQL/SquirrelMail,认证服务 LDAP, Kerberos, PAM,邮件通常存放在额外存储上还要 NFS/SAN,邮件服务 Postfix/Dovecot,反垃圾反病毒 Postgrey/Clam AV/SpamAssassion,安全认证 SSL,监控和备份等等,这一套下来基本包括了 Linux 系统管理的方方面面,所以说配置一个安全可靠的企业级邮件系统不容易,足够写一本书。个人配置邮件服务器通常不需要 LDAP/Kerbersos/NFS/SAN/SSL 这些,剔除这些后就不是那么复杂了,不过再想一下,个人有必要配置邮件服务器么?直接用免费的 Google App 不是很方便么。

准备工作

简单介绍一下我们将要安装的软件包:

  • Postfix: 用来接受和发送邮件的邮件服务器,正确说法应该叫邮件传送代理(Mail Transfer Agent,MTA),是邮件服务最重要的部分;
  • Dovecot: POP 和 IMAP 服务器,用来管理本地邮件目录以便用户能通过 Mail.app, Thunderbird, Mutt 等邮件客户端(又叫邮件用户代理 Mail User Agent, MUA)登陆和下载邮件;
  • Postgrey: 邮件灰名单工具,可简单的抵挡垃圾邮件;
  • amavisd-new: 一个代理,用于连接邮件传输代理和内容检查器,可以理解为 Postfix 把邮件交给它,它负责联系病毒扫描和垃圾邮件过滤;
  • Clam AntiVirus: 病毒扫描工具;
  • SpamAssassin: 垃圾邮件内容过滤工具;
  • Postfix Admin: Postfix 的 Web 前端,用来管理邮件用户和域名。

设置主机名(不要跳过这一步):

# hostname mail.vpsee.com

# vi /etc/hosts
127.0.0.1 mail.vpsee.com localhost

更新系统:

$ sudo apt-get update
$ sudo apt-get upgrade

安装必要软件包

安装 LAMP,Postfix 本身不需要 Apache/PHP/MySQL,但是因为要安装 Postfix Admin,并且管理用户需要用到数据库,所以要安装 Apache/PHP 和 MySQL.

$ sudo apt-get install lamp-server^
$ sudo apt-get install php-apc php5-curl php5-gd php-xml-parser php5-imap

安装邮件服务器及一些工具:

$sudo apt-get install mail-server^

$sudo apt-get install postfix-mysql dovecot-mysql postgrey
$sudo apt-get install amavis clamav clamav-daemon spamassassin

$sudo apt-get install libnet-dns-perl pyzor razor
$sudo apt-get install arj bzip2 cabextract cpio file gzip nomarch pax unzip zip

配置 Apache

编辑 apache 配置文件后重启:

$ sudo vi /etc/apache2/sites-available/default
...
    DocumentRoot /var/www
        <Directory />
                Options FollowSymLinks
                AllowOverride None
        </Directory>
...

$ sudo /etc/init.d/apache2 restart

配置 MySQL 数据库

创建一个名为 mail 的数据库并设置权限和密码:

$ mysql -uroot -p

mysql> create database mail;
mysql> grant all on mail.* to 'mail'@'localhost' identified by 'password';

配置 Postfix Admin

下载 psotfixadmin,解压后放到 /var/www:

$ wget http://downloads.sourceforge.net/project/postfixadmin/postfixadmin/postfixadmin-2.3.5/postfixadmin-2.3.5.tar.gz
$ gunzip postfixadmin-2.3.5.tar.gz
$ tar -xf postfixadmin-2.3.5.tar
$ sudo mv postfixadmin-2.3.5 /var/www/postfixadmin
$ sudo chown -R www-data:www-data /var/www/postfixadmin

配置 postfixamdin,标准的 php 程序配置方法,填入访问数据库需要的信息,其中 setup_password 部分稍后再填入:

$ sudo vi /var/www/postfixadmin/config.inc.php
...
$CONF['configured'] = true;
$CONF['setup_password'] = '稍后替代';
$CONF['postfix_admin_url'] = 'http://mail.vpsee.com/postfixadmin';
$CONF['database_type'] = 'mysql';
$CONF['database_host'] = 'localhost';
$CONF['database_user'] = 'mail';
$CONF['database_password'] = 'password';
$CONF['database_name'] = 'mail';
$CONF['admin_email'] = '[email protected]';
$CONF['encrypt'] = 'md5crypt';
...

用浏览器访问 http://mail.vpsee.com/postfixadmin/setup.php,用哈希后的密码字符串替代上面 $CONF[‘setup_password’] = ‘稍后替代’ 中的相关部分。

为了安全考虑,最好禁止 web 访问 setup.php:

$ sudo vi /var/www/postfixadmin/.htaccess

deny from all

配置 Dovecot

给系统添加 vmail 帐号:

$ sudo useradd -r -u 150 -g mail -d /var/vmail -s /sbin/nologin -c "Virtual Mail" vmail
$ sudo mkdir /var/vmail
$ sudo chmod 770 /var/vmail
$ sudo chown vmail:mail /var/vmail

开始配置 Dovecot,dovecot 支持多种认证方式,这里采用数据库认证,注意下面的配置文件一个包含一个,初看比较乱,10-auth.conf 有 !include auth-sql.conf.ext 一行,会包含 /etc/dovecot/conf.d/auth-sql.conf.ext,而 auth-sql.conf.ext 会包含下面要提到的 /etc/dovecot/dovecot-sql.conf.ext,这样只要用不同的 include 就可以切换不同的认证方式,虽然初看复杂一点但是熟悉以后用起来还是挺方便的。

$ sudo vi /etc/dovecot/conf.d/10-auth.conf

disable_plaintext_auth = yes
auth_mechanisms = plain login

!include auth-sql.conf.ext

配置 Dovecot,设置数据库参数,以便 dovecot 能正确访问刚才创建的 mail 数据库:

$ sudo vi /etc/dovecot/dovecot-sql.conf.ext
...
driver = mysql
connect = host=localhost dbname=mail user=mail password=password
default_pass_scheme = MD5-CRYPT
...
password_query = \
  SELECT username as user, password, '/var/vmail/%d/%n' as userdb_home, \
  'maildir:/var/vmail/%d/%n' as userdb_mail, 150 as userdb_uid, 8 as userdb_gid \
  FROM mailbox WHERE username = '%u' AND active = '1'

user_query = \
  SELECT '/var/vmail/%d/%n' as home, 'maildir:/var/vmail/%d/%n' as mail, \
  150 AS uid, 8 AS gid, concat('dirsize:storage=', quota) AS quota \
  FROM mailbox WHERE username = '%u' AND active = '1'
...

用户在服务器上用来存放邮件的地方在哪呢?所以需要指定邮件存放地址 /var/vmail,这个目录上面在创建 vmail 帐号时已经创建了:

$ sudo vi /etc/dovecot/conf.d/10-mail.conf
...
mail_location = maildir:/var/vmail/%d/%n
mail_uid = vmail
mail_gid = mail
...

修改 /etc/dovecot/conf.d/10-master.conf

$ sudo vi /etc/dovecot/conf.d/10-master.conf
...
service auth {
  unix_listener auth-userdb {
   mode = 0600
    user = vmail
    group = mail
  }
  unix_listener /var/spool/postfix/private/auth {
    mode = 0660
    user = postfix
    group = postfix        
  }
...

确认 dovecot 有权限读取配置文件:

$ sudo chown -R vmail:dovecot /etc/dovecot
$ sudo chmod -R o-rwx /etc/dovecot

配置 Amavis, ClamAV, SpamAssassin

互加 clamav, amavis 用户到对方组里以便能互相访问,配置过滤模式:

$ sudo adduser clamav amavis
$ sudo adduser amavis clamav

$ sudo vi /etc/amavis/conf.d/15-content_filter_mode
use strict;
@bypass_virus_checks_maps = (
   \%bypass_virus_checks, \@bypass_virus_checks_acl, \$bypass_virus_checks_re);
@bypass_spam_checks_maps = (
   \%bypass_spam_checks, \@bypass_spam_checks_acl, \$bypass_spam_checks_re);
1; # ensure a defined return

启用 spamassassin:

$ sudo vi /etc/default/spamassassin
...
ENABLED=1
CRON=1
...

配置 Postfix

main.cf 是 postfix 的主要配置文件:

$ sudo /etc/postfix/main.cf
...
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_auth_enable = yes

myhostname = mail.vpsee.com
myorigin = /etc/hostname
mydestination = mail.vpsee.com, localhost
mynetworks = 127.0.0.0/8
inet_interfaces = all
mynetworks_style = host

virtual_mailbox_base = /var/vmail/
virtual_alias_maps = mysql:/etc/postfix/mysql_virtual_alias_maps.cf, mysql:/etc/postfix/m
ysql_virtual_alias_domainaliases_maps.cf
virtual_mailbox_domains = mysql:/etc/postfix/mysql_virtual_domains_maps.cf

mail_spool_directory = /var/mail
virtual_transport = dovecot
dovecot_destination_recipient_limit = 1

content_filter = amavis:[127.0.0.1]:10024

header_checks = regexp:/etc/postfix/header_checks
...

注意上面配置有行 header_checks = regexp:/etc/postfix/header_checks,我们现在还没有 header_checks 文件,创建一个并包含一下内容,给自己邮件增加一点隐私,过滤一些信息:

$ sudo vi /etc/postfix/header_checks
/^Received:/                 IGNORE
/^User-Agent:/               IGNORE
/^X-Mailer:/                 IGNORE
/^X-Originating-IP:/         IGNORE
/^x-cr-[a-z]*:/              IGNORE
/^Thread-Index:/             IGNORE

还需要配置 master.cf 文件:

$ sudo vi /etc/postfix/master.cf
...
smtps     inet  n       -       -       -       -       smtpd
  -o syslog_name=postfix/smtps
  -o smtpd_tls_wrappermode=yes
  -o smtpd_sasl_auth_enable=yes
  -o smtpd_tls_auth_only=yes
  -o smtpd_client_restrictions=permit_sasl_authenticated,reject_unauth_destination,reject
  -o smtpd_sasl_security_options=noanonymous,noplaintext
  -o smtpd_sasl_tls_security_options=noanonymous

amavis      unix    -       -       -       -       2       smtp
  -o smtp_data_done_timeout=1200
  -o smtp_send_xforward_command=yes
  -o disable_dns_lookups=yes
  -o max_use=20
127.0.0.1:10025 inet    n       -       -       -       -       smtpd
  -o content_filter=
  -o local_recipient_maps=
  -o relay_recipient_maps=
  -o smtpd_restriction_classes=
  -o smtpd_delay_reject=no
  -o smtpd_client_restrictions=permit_mynetworks,reject
  -o smtpd_helo_restrictions=
  -o smtpd_sender_restrictions=
  -o smtpd_recipient_restrictions=permit_mynetworks,reject
  -o smtpd_data_restrictions=reject_unauth_pipelining
  -o smtpd_end_of_data_restrictions=
  -o mynetworks=127.0.0.0/8
  -o smtpd_error_sleep_time=0
  -o smtpd_soft_error_limit=1001
  -o smtpd_hard_error_limit=1000
  -o smtpd_client_connection_count_limit=0
  -o smtpd_client_connection_rate_limit=0
  -o receive_override_options=no_header_body_checks,no_unknown_recipient_checks

dovecot      unix   -        n      n       -       -   pipe
  flags=DRhu user=vmail:mail argv=/usr/lib/dovecot/dovecot-lda -d $(recipient)

还需要配置几个文件:

$ sudo vi /etc/postfix/mysql_virtual_alias_domainaliases_maps.cf
user = mail
password = password
hosts = 127.0.0.1
dbname = mail
query = SELECT goto FROM alias,alias_domain
  WHERE alias_domain.alias_domain = '%d'
  AND alias.address=concat('%u', '@', alias_domain.target_domain)
  AND alias.active = 1

$ sudo vi /etc/postfix/mysql_virtual_alias_maps.cf
user = mail
password = password
hosts = 127.0.0.1
dbname = mail
table = alias
select_field = goto
where_field = address
additional_conditions = and active = '1'

$ sudo vi /etc/postfix/mysql_virtual_domains_maps.cf
user = mail
password = password
hosts = 127.0.0.1
dbname = mail
table = domain
select_field = domain
where_field = domain
additional_conditions = and backupmx = '0' and active = '1'

$ sudo vi /etc/postfix/mysql_virtual_mailbox_domainaliases_maps.cf
user = mail
password = password
hosts = 127.0.0.1
dbname = mail
query = SELECT maildir FROM mailbox, alias_domain
  WHERE alias_domain.alias_domain = '%d'
  AND mailbox.username=concat('%u', '@', alias_domain.target_domain )
  AND mailbox.active = 1

$ sudo vi /etc/postfix/mysql_virtual_mailbox_maps.cf
user = mail
password = password
hosts = 127.0.0.1
dbname = mail
table = mailbox
select_field = CONCAT(domain, '/', local_part)
where_field = username
additional_conditions = and active = '1'

大功告成,重启相关服务:

$ sudo service spamassassin restart
$ sudo service clamav-daemon restart
$ sudo service amavis restart
$ sudo service dovecot restart
$ sudo service postfix restart

测试 Postfix

用 telnet 连上邮件服务器的 25 端口(SMTP),然后发送 HELO mail.vpsee.com 指令就会得到 250 mail.vpsee.com 确认信息:

$ telnet mail.vpsee.com 25 
Trying 192.168.2.66...
Connected to mail.vpsee.com.
Escape character is '^]'.
220 mail.vpsee.com ESMTP Postfix (Ubuntu)
HELO mail.vpsee.com
250 mail.vpsee.com

用 telnet 发送一封邮件试一下,下面的 MAIL FROM, RCPT TO, DATA, ., QUIT 都是指令:

$ telnet mail.vpsee.com 25 
Trying 192.168.2.66...
Connected to mail.vpsee.com.
Escape character is '^]'.
220 mail.vpsee.com ESMTP Postfix (Ubuntu)
MAIL FROM:<[email protected]>
250 2.1.0 Ok
RCPT TO:<[email protected]>
250 2.1.5 Ok
DATA
354 End data with <CR><LF>.<CR><LF>
Subject: a test message
This is a test message!
.
250 2.0.0 Ok: queued as 6832FF0036
QUIT
221 2.0.0 Bye
Connection closed by foreign host.

ssh 登陆邮件服务器后去 /var/vmail 邮件目录看一下就可以证实 test2 用户是否收到来自 test1 用户的邮件,当然这个邮件也可以通过 Mail.app, Thunderbird, Mutt 这类工具收到本地电脑上看

使用 mutt, fetchmail, maildrop, msmtp 收发邮件

现在已经有了 Mail.app, Thunderbird, Outlook 这些图形化工具能很方便的处理邮件,为啥还需要 mutt 这种命令行文本方式的邮件工具呢?mutt 的一个优势是占用资源小,可以很好的运行在低配置的虚拟机或古老的电脑上(应该不会有人想在 256MB 内存的虚拟机或 VPS 上用 X Window/Gnome/Thunderbird 这种组合吧)。那为什么要在虚拟机上收发邮件呢,不能在自己电脑上处理邮件吗?可能有多个电脑而且电脑经常换,电脑可能被盗,硬盘可能坏、数据可能丢,邮件放在本地电脑不太方便,有些电脑可能是共用的,在共用电脑上保留自己的邮件帐号不爽。那为啥不直接用 Gmail 收发 POP/IMAP 工作邮件呢?有时候可能需要在别人的电脑上打开工作邮件,比如核对一些事情、计划、会议记录之类的,在公共电脑或者别人电脑上开自己的私人邮箱是件很危险的事情,谁知道电脑上有没有病毒、木马或者键盘纪录程序?

建议经常使用 Gmail 的用户激活 2-step verification 增加安全性。

总之吧,现在的需求是:ssh 到一台服务器或虚拟机上,用 mutt 处理邮件。

在 Ubuntu 上

在 Ubuntu 上安装 mutt + fetchmail + maildrop + msmtp:

# apt-get install mutt fetchmail maildrop msmtp

在 FreeBSD 上

在 FreeBSD 上安装 mutt + fetchmail + maildrop + msmtp:

# pkg_add -r mutt
# pkg_add -r fetchmail
# pkg_add -r maildrop
# pkg_add -r msmtp

配置 mutt

touch 一个文件用来存放邮件:

# mkdir /var/spool/mail
# touch /var/spool/mail/vpsee

配置 fetchmail 通过 POP 收邮件:

$ vi .fetchmailrc
poll "mail.vpsee.com"
protocol pop3
username "vpsee"
password "password"
mimedecode                      # 自动处理 mime 
mda "/usr/bin/maildrop"         # 告诉 fetchmail 使用哪个 MDA (for Ubuntu)
#mda "/usr/local/bin/maildrop"  # 告诉 fetchmail 使用哪个 MDA (for FreeBSD)

$ chmod 0700 .fetchmailrc

配置 maildrop,告诉 maildrop 把邮件分发到哪里(其实是一个 /var/spool/mail/ 下的一个文件),注意这个时候要处理一下权限问题,否则用户登陆执行 fetchmail 后由 maildrop 分发到邮箱( /var/spool/mail/vpsee)的时候会出现权限错误(因为 maildrop 没有权限写那个文件):

# touch /var/spool/mail/vpsee
# chown vpsee:vpsee /var/spool/mail/vpsee

$ vi .mailfilter
HOME=/home/vpsee              # 指定 home 目录
DEFAULT=/var/spool/mail/vpsee # 想在哪里保持邮件
logfile "$HOME/.maillog"      # 日志

配置 msmtp 用 SMTP 发邮件:

$ vi .msmtprc
account default
host mail.vpsee.com
from [email protected]
auth off

配置 mutt,在 mutt 配置文件里面指明 msmtp 路径,注意 Ubuntu 和 FreeBSD 的默认安装路径不同(/usr/bin vs /usr/local/bin)

$ vi .muttrc
set realname            = "vpsee"
set from                = "[email protected]"
set use_from            = yes
set envelope_from       = yes
set spoolfile           = /var/spool/mail/vpsee
set sendmail="/usr/bin/msmtp" # for Ubuntu
#set sendmail="/usr/local/bin/msmtp" # for FreeBSD

使用 mutt

执行 fetchmail 收邮件,然后就可以用 mutt 读、写、回复邮件了:

$ fetchmail -v

$ mutt

mutt

使用 collectd 和 Graphite 监控服务器

Graphite 只是一个数据绘图工具,安装 Graphite 完以后啥也不能干,需要其他工具喂它数据,所以具体的数据采集工作是由第三方工具完成,Graphite 的设计体现了 Unix 的思想:只做一件事,把事情做好。Graphite 支持的第三方工具很多,Bucky, collectd, Collectl, Charcoal, Diamond, Ganglia, Host sFlow, statsd, Tasseo 等等。这里 VPSee 选用 collectd 来收集机器的各个性能参数,collectd 安装在需要被监控的机器上。

安装 collectd,创建一个 collectd.d 目录便于存放稍后会遇到的插件配置文件 graphite.conf,并在 collectd.conf 包含这个目录 :

$ sudo apt-get install collectd

$ sudo mkdir /etc/collectd/collectd.d
$ sudo vi /etc/collectd/collectd.conf
...
Include      "/etc/collectd/collectd.d"

安装 git 并下载 collectd-carbon 插件:

$ sudo apt-get install git

$ sudo git clone https://github.com/indygreg/collectd-carbon.git /opt/collectd-plugins

修改插件的配置文件的 ModulePath 部分,指向 carbon_writer.py 文件所在目录,并且修改 LineReceiverHost 部分:

$ sudo vi /etc/collectd/collectd.d/graphite.conf
<LoadPlugin "python">
    Globals true
</LoadPlugin>

<Plugin "python">
    # carbon_writer.py is at path /opt/collectd-plugins/carbon_writer.py
    ModulePath "/opt/collectd-plugins/"

    Import "carbon_writer"

    <Module "carbon_writer">
        LineReceiverHost "monitor.vpsee.com"
        LineReceiverPort 2003
        DifferentiateCountersOverTime true
        LowercaseMetricNames true
        TypesDB "/usr/share/collectd/types.db"
    </Module>
</Plugin>

修改好配置文件后重启服务:

$ sudo /etc/init.d/collectd restart

大功告成,等着客户端的 collectd 收集数据发送给监控服务器的 carbon(监听端口为 2003)吧,然后递交给 graphite 绘制图形。

在 Ubuntu 12.04 上安装 Graphite 监控工具

有几个朋友都跟我提过 Graphite,监控工具里面的新秀,一直都没时间关注,最近把 n 台物理服务器用 Puppet 代码化的任务完成后有了不少空闲时间,抽时间看了看 Graphite,先搜了一下中文想看看大家对这个工具有啥看法,居然没人提到这个工具,哪怕一篇博客一个帖子都没有??

常收到一些学生朋友来信,问到一些 Linux、计算机方面的学习建议,VPSee 能给的第一个建议是学好英语,优秀的技术人员必须能熟练的翻阅英文资料,大家也看到了,可用的中文资料真的不多,虽然英文会议我们可以不去、英文技术会议的视频也可以不看,但是平时的一些技术交流邮件、Github、Mailing list、经典技术书籍、文档、好的技术博客等都需要英文。Eric Steven Raymond 在他的那篇有名的 How To Become A Hacker 里也提到了:

If you don’t have functional English, learn it.

如果不能用英语交流,Linus Torvalds 写出来的 Linux 可能也就出不了芬兰,也不会有今天的成功。

废话打住,来看 Graphite.

Graphite 是一个(可运行在廉价硬件上的)企业级开源监控工具,用于采集服务器实时信息并进行统计,可采集 n 个服务器实时状态,如:用户请求消息,Memcached 命中率,RabbitMQ 消息服务器状态、操作系统负载、等等。Graphite 使用 Python 编写,采用 Django 框架,使用自己的简单文本协议通讯,服务平均每分钟有4800次更新操作,简单的文本协议和强大的绘图功能可以方便地扩展到任何需要监控的系统上。

和其他监控工具不同的是,Graphite 自己本身并不收集具体的数据,这些数据收集的具体工作通常由第三方工具或插件完成(如 Ganglia, collectd, statsd, Collectl 等,参考:使用 collectd 和 Graphite 监控服务器)。所以上面说 “Graphite 是一个系统监控工具” 的说法不完全正确,更准确的说法应该是 “Graphite 是一个数据绘图工具”,得到数据后绘图,它并不关心具体数据,你甚至可以把每天收到的邮件数当作参数传给 Graphite 制成图,然后一段时间后就生产一个漂亮的邮件繁忙展示图,并可以看出趋势。

简单的说,Graphite 做两件事:1、存储数据;2、按需绘图。

安装必要软件包:

$ sudo apt-get install apache2 libapache2-mod-wsgi python-django \
python-twisted python-cairo python-pip python-django-tagging

用 pip 安装 whisper (简单的存放和操作数据的库), carbon (监控数据的 Twisted 守护进程) 和 graphite-web (Django webapp):

$ sudo pip install whisper
$ sudo pip install carbon
$ sudo pip install graphite-web

初始化配置,直接用 example 文件里的默认配置就可以:

$ cd /opt/graphite/conf/

$ sudo cp carbon.conf.example carbon.conf
$ sudo cp storage-schemas.conf.example storage-schemas.conf
$ sudo cp graphite.wsgi.example graphite.wsgi

修改 apache 配置,增加一个 vhost 或者偷懒下载一个配置文件覆盖 default,覆盖后需要重新 reload 配置:

$ wget http://launchpad.net/graphite/0.9/0.9.9/+download/graphite-web-0.9.9.tar.gz
$ tar -zxvf graphite-web-0.9.9.tar.gz
$ cd graphite-web-0.9.9
$ sudo cp examples/example-graphite-vhost.conf /etc/apache2/sites-available/default

sockets 最好不要放在 /etc/httpd/ 下面(不同 Linux 发行版本对不同目录的权限问题很混淆人),ubuntu 版本可以放在 /var/run/apache2 下,所以修改 default 文件里的 WSGISocketPrefix 部分:

$ sudo vi /etc/apache2/sites-available/default
...
WSGISocketPrefix /var/run/apache2/wsgi
...

$ sudo /etc/init.d/apache2 reload

初始化 graphite 需要的数据库,修改 storage 的权限,用拷贝的方式创建 local_settings.py 文件:

$ cd /opt/graphite/webapp/graphite/

$ sudo python manage.py syncdb
$ sudo chown -R www-data:www-data /opt/graphite/storage/
$ sudo cp local_settings.py.example local_settings.py

$ sudo /etc/init.d/apache2 restart

启动 carbon:

$ cd /opt/graphite/

$ sudo ./bin/carbon-cache.py start

浏览器访问 IP 地址后就可以看到 graphite web 界面:
graphite

如何使用 Example42 的 Puppet 模块

现在我们差不多移植了100多台服务器到虚拟机,中间合并了很多功能类似的服务器(历史遗留问题)到同一虚拟机,并且整个配置过程完全用 Puppet 代码化,也就是说有一天我们实验室机房遭遇物理毁灭(刚看完 Battleship,有点激动~),只要再给我们合适的硬件设备(异地有备份数据)我们应该能在6小时内恢复整个基础设施(OS, DNS, DHCP, Provision, Firewall, Squid, Web, Database, LDAP, Email, VPN, Kerberos, NFS, HPC, Cloud, Monitor, Backup, …)。自从 Puppet/Chef 之类的自动化配置工具流行以后,现在甚至有了一个新职位叫做 DevOps.

安装好 Puppet 后,就可以开始自己写配置代码了,当然也可以在网上找到别人的配置代码直接拿过来用,更妙的是一些通用的 Puppet 配置代码,比如配置一台 Nginx/PHP/MySQL、配置 NFS、配置 DHCP、配置 DNS、配置 OpenNebula 等等已经有人写成模块了,直接拷过来就可以用了。Example42 就是这样的开源 Puppet 模块大集合,包含了众多常用的服务器配置。

首先去 Example42 下载 Puppet 模块代码:

$ git clone http://github.com/example42/puppet-modules.git

看看 Example42 包含了哪些模块吧,几乎常用的都有,不用自己亲自去写配置:

$ cd puppet-modules/
$ ls
DOCS		example42	mysql		puppi		synbak
Example42-tools	exim		nagios		rails		sysctl
LICENSE		firewall	network		redis		sysklogd
README.rdoc	foo		nfs		repo		syslog-ng
Rakefile	foreman		nginx		resolver	tftp
activemq	git		nrpe		rootmail	timezone
apache		haproxy		ntp		rpmbuild	tomcat
apt		hardening	openldap	rsync		trac
autofs		hosts		openntpd	rsyslog		users
backup		iptables	openssh		samba		vagrant
bind		jboss		openvpn		sarg		varnish
clamav		jenkins		oracle		selinux		virtualbox
cobbler		lighttpd	pam		sendmail	vmware
collectd	link		php		snmpd		vsftpd
common		logrotate	phpsyslogng	spamassassin	wordpress
concat		lsb		portmap		splunk		xinetd
controltier	mailscanner	postfix		sqlgrey		yum
cron		mailx		postgresql	squid		zip
dashboard	mcollective	powerdns	squirrelmail
dhcpd		monit		psad		ssh
dovecot		monitor		psick		ssmtp
drupal		munin		puppet		stdlib42

把上面的 Example42 代码移到 /etc/puppet 目录,然后修改 Puppet 服务器的配置,加上 puppet-modules 模块路径,别忘了重启 puppetmaster 服务:

# mv puppet-modules /etc/puppet

# vi /etc/puppet/puppet.conf
...
[master]
    modulepath = /etc/puppet/puppet-modules

# /etc/init.d/puppetmaster

写个配置文件测试一下,自动配置 PHP + Apache + MySQL:

# vi /etc/puppet/manifests/node.pp

node 'web.vpsee.com' {
    include apache

    include php
    include php::pear
    include php::apc
    php::module { mysql: }
    php::module { curl: }
    php::module { gd: }
    php::module { idn: }
    php::module { imagick: }
    php::module { imap: }
    php::module { mcrypt: }
    php::module { ming: }
    php::module { ps: }
    php::module { pspell: }
    php::module { recode: }
    php::module { snmp: }
    php::module { tidy: }
    php::module { xmlrpc: }
    php::module { xsl: }
    php::module { ldap: }

    include mysql
}

在要配置的机器上执行下面一条命令就自动装上 Apache/PHP/MySQL 了,再不用自己手动去安装配置了:

# puppet agent --test --server=master.vpsee.com

如何在 Cobbler 上导入和启动 Ubuntu

Cobbler 在 CentOS/RHEL/Fedora 系的发行版上工作良好,在 CentOS/RHEL/Fedora 上安装 Cobbler 以后可以直接导入 CentOS/RHEL/Fedora ISO 文件,很顺利,不过导入 Ubuntu/Debian ISO 就不是那么幸运了,直接导入 ubuntu-11.10-server-amd64.iso 的话会报错:

# cobbler import –path=/mnt/ –name=ubuntu-11.10-server-amd64
...
sent 710595315 bytes  received 36388 bytes  52639385.41 bytes/sec
total size is 710349452  speedup is 1.00
...
!!! TASK FAILED !!!

忽略上面的错误,会发现在 ks_mirror 下面已经导入了 ubuntu-11.10-server-amd64 整个 ubuntu 目录:

# ls /var/www/cobbler/ks_mirror/
config  ubuntu-11.10-server-amd64

如果对上面已经导入的 ubuntu 目录还不放心的话,可以删除这个目录后手动导入(直接 cp 就行):

# rm -rf /var/www/cobbler/ks_mirror/ubuntu-11.10-server-amd64

# mount -o loop -t iso9660 ubuntu-11.10-server-amd64.iso /mnt

# cp -r /mnt/ /var/www/cobbler/ks_mirror/ubuntu-11.10-server-amd64

完成导入(拷贝)后,做个链接:

# cd /var/www/cobbler/links/
# ln -s /var/www/cobbler/ks_mirror/ubuntu-11.10-server-amd64 ubuntu-11.10-server-amd64

然后加入 distro 和 profile:

# cobbler distro add \
--name=ubuntu-11.10-server-amd64 \
--kernel=/var/www/cobbler/ks_mirror/ubuntu-11.10-server-amd64/install/netboot/ubuntu-installer/amd64/linux \
--initrd=/var/www/cobbler/ks_mirror/ubuntu-11.10-server-amd64/install/netboot/ubuntu-installer/amd64/initrd.gz \
--arch=x86_64 \
--breed=ubuntu \
--ksmeta="directory=/cblr/links/ubuntu-11.10-server-amd64"

# cobbler profile add \
--name=ubuntu-11.10-server-amd64 \
--distro=ubuntu-11.10-server-amd64 \
--kickstart=/var/lib/cobbler/kickstarts/ubuntu-11.10-server-amd64.seed

最后我们需要 ubuntu 能完成自动安装,加入以下 kickstart 脚本 ubuntu-11.10-server-amd64.seed 到 /var/lib/cobbler/kickstarts/ :

# vi /var/lib/cobbler/kickstarts/ubuntu-11.10-server-amd64.seed
d-i     debian-installer/locale string en_US.UTF-8
d-i     debian-installer/splash boolean false
d-i     console-setup/ask_detect        boolean false
d-i     console-setup/layoutcode        string us
d-i     console-setup/variantcode       string
d-i     netcfg/get_nameservers  string
d-i     netcfg/get_ipaddress    string
d-i     netcfg/get_netmask      string 255.255.255.0
d-i     netcfg/get_gateway      string
d-i     netcfg/confirm_static   boolean true
d-i     clock-setup/utc boolean true
d-i     partman-auto/method string regular
d-i     partman-lvm/device_remove_lvm boolean true
d-i     partman-lvm/confirm boolean true
d-i     partman/confirm_write_new_label boolean true
d-i     partman/choose_partition        select Finish partitioning and write changes to disk
d-i     partman/confirm boolean true
d-i     partman/confirm_nooverwrite boolean true
d-i     partman/default_filesystem string ext3
d-i     clock-setup/utc boolean true
d-i     clock-setup/ntp boolean true
d-i     clock-setup/ntp-server  string ntp.ubuntu.com
d-i     base-installer/kernel/image     string linux-server
d-i     passwd/root-login       boolean false
d-i     passwd/make-user        boolean true
d-i     passwd/user-fullname    string ubuntu
d-i     passwd/username string ubuntu
d-i     passwd/user-password-crypted    password $default_password_crypted
d-i     passwd/user-uid string
d-i     user-setup/allow-password-weak  boolean false
d-i     user-setup/encrypt-home boolean false
d-i     passwd/user-default-groups      string adm cdrom dialout lpadmin plugdev sambashare
d-i     apt-setup/services-select       multiselect security
d-i     apt-setup/security_host string security.ubuntu.com
d-i     apt-setup/security_path string /ubuntu
d-i     debian-installer/allow_unauthenticated  string false
d-i     pkgsel/upgrade  select safe-upgrade
d-i     pkgsel/language-packs   multiselect
d-i     pkgsel/update-policy    select none
d-i     pkgsel/updatedb boolean true
d-i     grub-installer/skip     boolean false
d-i     lilo-installer/skip     boolean false
d-i     grub-installer/only_debian      boolean true
d-i     grub-installer/with_other_os    boolean true
d-i     finish-install/keep-consoles    boolean false
d-i     finish-install/reboot_in_progress       note
d-i     cdrom-detect/eject      boolean true
d-i     debian-installer/exit/halt      boolean false
d-i     debian-installer/exit/poweroff  boolean false
d-i     pkgsel/include string openssh-server

在 CentOS 6.2 上安装 Cobbler

每次給自己的电脑重装系统都是一件很无聊的事情,如果需要重装上百台虚拟机和服务器不但很无聊而且很耗时,面对现在云时代大量服务器和虚拟机的出现,运维必须要自动化。现在有很多开源工具可以帮助我们实现自动化安装系统,比如 FAI, Cobbler, Spacewalk, Ubuntu Orchestra 等,我们打算把 Cobbler 安装在某台虚拟机上,为我们新购的16台刀片服务器自动安装系统。

Cobbler 是一个系统启动服务(boot server),可以通过网络启动(PXE)的方式用来快速安装、重装物理服务器和虚拟机,支持安装不同的 Linux 发行版和 Windows. Cobbler 是个轻量级 Python 程序,总共大概1.5万行代码,还可以用来管理 DHCP, DNS, yum 源等。Cobbler 使用命令行方式管理,也提供了基于 Web 的界面管理工具(cobbler-web),不过命令行方式已经很方便,实在没有必要为了不实用的 Web 界面再添加一个 Web 服务器。

修改 DHCP 服务器配置

使用 Cobbler 最好配合现有局域网上的 DHCP 服务器一起使用,这样不会因为 Cobbler 干扰现有局域网。我们不打算用 Cobbler 来管理整个网络的 DHCP,因为我们已经有了 DHCP 服务器,所以只要在现有的 DHCP 服务器上做以下配置即可,下面记得调整 192.168.2.22 这个 IP 地址指向 Cobbler 服务器:

# for Cobbler setup
host cobbler {
    option host-name "cobbler";
    ddns-hostname "cobbler";
    hardware ethernet 00:0c:29:2d:2c:39; #MAC address of cobbler server
            fixed-address 192.168.2.22; #IP of Cobbler server
            allow booting;
    allow bootp;
    class "PXE" {
        match if substring(option vendor-class-identifier, 0, 9) = "PXEClient";
        next-server 192.168.2.22; #IP of Cobbler server
            filename "pxelinux.0";
    }
}

安装和配置 Cobbler

Cobbler 不在 CentOS 6.2 的基本源中,需要导入 EPEL 源:

# rpm -Uvh http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-5.noarch.rpm
Retrieving http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-5.noarch.rpm
warning: /var/tmp/rpm-tmp.lo2Hd0: Header V3 RSA/SHA256 Signature, key ID 0608b895: NOKEY
Preparing...                ########################################### [100%]
   1:epel-release           ########################################### [100%]

# yum update
# yum upgrade

安装 cobbler:

# yum install cobbler

修改配置,主要修改 cobbler 服务器所在的 IP 地址:

# vi /etc/cobbler/settings
...
next_server: 192.168.2.22 #IP of Cobbler server
server: 192.168.2.22 #IP of Cobbler server
...

启用 httpd, xinetd 和 cobbler 服务并确认已经加到系统自动启动服务中:

# /etc/init.d/httpd start
# /etc/init.d/xinetd start
# /etc/init.d/cobblerd start

# chkconfig httpd on
# chkconfig xinetd on
# chkconfig cobblerd on

修改 rsync 和 tftp 这两个服务的 xinetd 配置:

# vi /etc/xinetd.d/rsync
service rsync
{
        disable = no
...
}

# vi /etc/xinetd.d/tftp
service tftp
{
        ...
        disable = no
        ...
}

关闭防火墙和 SELinux 后重启系统:

# /etc/init.d/iptables stop
# chkconfig iptables off

# vi /etc/sysconfig/selinux
...
SELINUX=disabled
...

# reboot

检查和修改 Cobbler 配置

系统重启后用 cobbler check 检查发现3个配置信息问题,第一个是如果要部署 debian/ubuntu 系统需要 debmirror 软件包;第二个是需要修改 cobbler 的默认密码;第三个是可选,想使用电源管理功能的话需要安装 cman 或 fence-agents:

# cobbler get-loaders

# cobbler check
The following are potential configuration items that you may want to fix:

1 : debmirror package is not installed, it will be required to manage debian deployments and repositories
2 : The default password used by the sample templates for newly installed machines (default_password_crypted in /etc/cobbler/settings) is still set to 'cobbler' and should be changed, try: "openssl passwd -1 -salt 'random-phrase-here' 'your-password-here'" to generate new one
3 : fencing tools were not found, and are required to use the (optional) power management features. install cman or fence-agents to use them

Restart cobblerd and then run 'cobbler sync' to apply changes.

现在来修复上面三个问题,我们希望能让这台 cobbler 服务器能同时部署 CentOS/Fedora 和 Debian/Ubuntu 系统,所以需要安装 debmirror,安装 debmirror-20090807-1.el5.noarch.rpm 前需要先安装依赖包:

# yum install wget
# yum install ed patch perl perl-Compress-Zlib perl-Cwd perl-Digest-MD5 \
perl-Digest-SHA1 perl-LockFile-Simple perl-libwww-perl

# wget ftp://fr2.rpmfind.net/linux/epel/5/ppc/debmirror-20090807-1.el5.noarch.rpm

# rpm -ivh debmirror-20090807-1.el5.noarch.rpm 

修改 /etc/debmirror.conf 配置文件,注释掉 @dists 和 @arches 两行:

# vi /etc/debmirror.conf
...
#@dists="sid";
@sections="main,main/debian-installer,contrib,non-free";
#@arches="i386";
...

用 openssl 生成一串密码后加入到 cobbler 的配置文件(/etc/cobbler/settings)里,替换 default_password_crypted 字段:

# openssl passwd -1 -salt 'www.vpsee.com' 'vpsee'
$1$www.vpsee$T5FgCHY2P0NDr6JmbN0Bl0

# vi /etc/cobbler/settings
default_password_crypted: "$1$www.vpsee$T5FgCHY2P0NDr6JmbN0Bl0"

安装 cman:

# yum install cman

修复完成,再用 cobbler check 检查一下,确认没问题后用 cobbler sync 做同步操作:

# cobbler check
No configuration problems found.  All systems go.

# cobbler sync

导入 ISO

挂载 CentOS-6.2-x86_64-bin-DVD1.iso 安装光盘然后导入到 cobbler(注意这个 iso 文件有 4GB 多,导入可能需要一段时间),导入成功后 cobbler list 查看一下:

# mount -o loop -t iso9660 CentOS-6.2-x86_64-bin-DVD1.iso /mnt

# cobbler import --path=/mnt --name=CentOS-6.2-x86_64-bin-DVD1 –arch=x86_64

# cobbler sync

# cobbler list
distros:
   CentOS-6.2-bin-DVD1-x86_64

profiles:
   CentOS-6.2-bin-DVD1-x86_64

systems:

repos:

images:

测试

最后创建一台虚拟机测试一下,把虚拟机设置成网络 PXE 启动(和 cobbler 在同一个网络),启动后就可以看到 Cobbler 引导界面,看到界面后选择 CentOS-6.2-bin-DVD1-x86_64 条目就可以顺利开始无人工干预安装系统,Cobbler 引导界面如下:

boot os from cobbler net pxe

安装完系统后默认的密码是啥呢?根据 sample.ks 的配置提示,这个密码 $default_password_crypted 就是我们上面用 openssl passwd -1 -salt ‘www.vpsee.com’ ‘vpsee’ 生成的密码,所以这里的 root 密码是 vpsee:

# cat /var/lib/cobbler/kickstarts/sample.ks
...
#Root password
rootpw --iscrypted $default_password_crypted

在 CentOS 6.2 上安装 Puppet 配置管理工具

puppet logo

云计算时代系统管理员会经常陷入一系列的重复任务中,创建虚拟机,安装或重装系统,升级软件包,管理配置文件,添加、管理和配置系统服务等。这些任务低效而且无聊,我们需要把他们自动化,于是就出现了系统管理员自己写的脚本,用定制脚本实现自动化,但是自己写的脚本要保证能顺利运行在不同的平台上不是一件轻松的工作,每次操作系统更新都需要重新测试定制脚本,耗费大量时间和精力,灵活性和功能也很难保证。而且脚本语言虽然简单,但是自己写的脚本不一定别的管理员就能马上看懂,有时候自己看别人写的脚本或代码不是一件愉快的事情。所以出现了类似 Puppet, Chef 这样的自动化配置管理工具。为啥 Linode 只有19人就能应付上千服务器上万用户,这就是自动化带来的好处。

Puppet 是一个客户端/服务器(C/S)架构的配置管理工具,在中央服务器上安装 puppet-server 服务器(puppet master),在需要被管理的目标服务器上安装 puppet 客户端软件(puppet client)。当客户端连接上服务器后,定义在服务器上的配置文件会被编译,然后在客户端上运行。客户端每隔半小时主动会和服务器通信一次,确认配置信息的更新情况,如果有新的配置信息(或者配置有变化),配置文件将会被重新编译并分发到客户端执行。当然,也可以在服务器上主动触发更新指令来强制各客户端进行配置更新。

以下安装采用两台服务器,一台是 master.vpsee.com 用来安装 puppet-server 服务;一台是 client.vpsee.com 用来安装 puppet 客户端。

Puppet 要求所有机器有完整的域名(FQDN),如果没有 DNS 服务器提供域名的话,可以在两台机器上设置主机名(注意要先设置主机名再安装 Puppet,因为安装 Puppet 时会把主机名写入证书,客户端和服务端通信需要这个证书):

# vi /etc/hosts
192.168.2.10    master master.vpsee.com
192.168.2.11    client client.vpsee.com

Puppet 要求所有机器上的时钟保持同步,所以需要安装和启用 ntp 服务(如果采用 CentOS-6.2-x86_64-minimal.iso 最小化安装,需要额外安装这个软件包)。

# yum install ntp

# chkconfig ntpd on

# ntpdate pool.ntp.org
29 Feb 15:22:47 ntpdate[15867]: step time server 196.25.1.1 offset 98.750417 sec

# service ntpd start
Starting ntpd:                                             [  OK  ]

安装 puppet 服务

Puppet 需要 Ruby 的支持,如果要查看命令行帮助的话需要额外 ruby-rdoc 这个软件包:

# yum install ruby ruby-libs ruby-rdoc

Puppet 不在 CentOS 的基本源中,需要加入 PuppetLabs 提供的官方源:

# yum -y install wget

# wget http://yum.puppetlabs.com/el/6/products/x86_64/puppetlabs-release-6-1.noarch.rpm

# yum install puppetlabs-release-6-1.noarch.rpm

# yum update

在 master 上安装和启用 puppet 服务:

# yum install puppet-server

# chkconfig puppet on

# service puppetmaster start
Starting puppetmaster:                                     [  OK  ]

关闭 iptables:

# /etc/init.d/iptables stop
iptables: Flushing firewall rules:                         [  OK  ]
iptables: Setting chains to policy ACCEPT: filter          [  OK  ]
iptables: Unloading modules:                               [  OK  ]

安装 puppet 客户端

在 client 上安装 puppet 客户端:

# yum install puppet

Puppet 客户端使用 HTTPS 和服务端(master)通信,为了和服务器端通信必须有合法的 SSL 认证,第一次运行 puppet 客户端的时候会生成一个 SSL 证书并指定发给 Puppet 服务端。

# puppet agent --no-daemonize --onetime --verbose --debug --server=master.vpsee.com

Puppet 服务端接受到客户端的证书后必须签字(sign)才能允许客户端接入,sign 后用 puppet cert list –all 查看会发现 client.vpsee.com 前面多了一个 + 后,表示 “加入” 成功:

# puppet cert list --all
  client.vpsee.com (65:3C:20:82:AE:F6:23:A8:0A:0B:09:EF:05:64:1D:BB)
+ master.vpsee.com   (AF:A0:32:78:D4:EB:D3:EE:02:1C:62:1C:83:3C:46:EC) (alt names: DNS:master, DNS:master.vpsee.com)

# puppet cert --sign client.vpsee.com
notice: Signed certificate request for client.vpsee.com
notice: Removing file Puppet::SSL::CertificateRequest client.vpsee.com at '/var/lib/puppet/ssl/ca/requests/client.vpsee.com.pem'

# puppet cert list --all
+ client.vpsee.com (65:3C:20:82:AE:F6:23:A8:0A:0B:09:EF:05:64:1D:BB)
+ master.vpsee.com   (AF:A0:32:78:D4:EB:D3:EE:02:1C:62:1C:83:3C:46:EC) (alt names: DNS:master, DNS:master.vpsee.com)

这样,客户端和服务端就配置好了,双方可以通信了。

Hello, world

现在可以在服务端写个小例子来测试一下。这个例子作用很简单,用来在客户端的 /tmp 目录下新建一个 helloworld.txt 文件,内容为 hello, world. 在服务端编写代码:

# vi /etc/puppet/manifests/site.pp
node default {
        file {
                "/tmp/helloworld.txt": content => "hello, world";
        }
}

在客户端上执行 puppet,运行成功后会在 /tmp 看到新生成的 helloworld.txt:

$ puppet agent --test --server=master.vpsee.com
warning: peer certificate won't be verified in this SSL session
info: Caching certificate for client.vpsee.com
info: Caching certificate_revocation_list for ca
info: Caching catalog for client.vpsee.com
info: Applying configuration version '1330668451'
notice: /Stage[main]//Node[default]/File[/tmp/helloworld.txt]/ensure: defined content as '{md5}e4d7f1b4ed2e42d15898f4b27b019da4'
info: Creating state file /home/vpsee/.puppet/var/state/state.yaml
notice: Finished catalog run in 0.03 seconds

$ cat /tmp/helloworld.txt 
hello, world

如果想偷懒,可以直接使用 Example42 的开源 Puppet 模块

Linux 服务器因 CPU 温度过高自动 shutdown

昨天一台 Linux Xen 服务器莫名其妙就不能访问了,开始以为又碰到 server kernel: ip_conntrack: table full, dropping packet. 问题,没仔细看。后来过了2个小时又不能访问了,看了一下日志是服务器自己 shutdown 了,不是网络的问题。再看日志发现错误信息:

Nov 24 05:32:22 ivps kernel: ACPI: Critical trip point
Nov 24 05:32:22 ivps kernel: Critical temperature reached (76 C), shutting down.

原因是 CPU 温度过高超过了警戒温度,查一下系统默认的警戒温度是75度,所以到了76度系统就自动 shutdown 了:

# cat /proc/acpi/thermal_zone/THRM/trip_points 
critical (S5):           75 C

服务器温度有这么高吗?查看一下当前温度吓一跳,刚启动的系统又到了74度,系统马上又要 shutdown 了:

# cat /proc/acpi/thermal_zone/THRM/temperature 
temperature:             74 C

紧急做法是暂时修改默认报警温度到85度:

# echo 85:0:80:60:0 > /proc/acpi/thermal_zone/THRM/trip_points

# cat /proc/acpi/thermal_zone/THRM/trip_points 
critical (S5):           85 C

一般来说 CPU 温度超过70度都是很高的温度了,如果不是系统和程序的原因要赶紧检查服务器周围的环境,检查机房和机柜温度情况、服务器风扇、内部积灰等,让 CPU 和主板长时间工作在高温下可不是好事情。当然不同 CPU 所能耐的住的温度也不同,VPSee 推荐 Intel Core 2 Quad CPU 保持在70度以下,Intel Core i7 CPU 保持在80度以下,这样 CPU 和系统能全速工作发挥最大效率而温度又不至于损坏 CPU.

服务器出现 server kernel: ip_conntrack: table full, dropping packet. 问题

昨天上午挂在 VPSee 桌子旁边墙壁上的老古董 IBM TP600E 终于发挥作用,连续报警,监视显示某台服务器丢包非常严重,甚至大多时候不能访问,终端登录系统后检查日志发现 ip_conntrack: table full, dropping packet. 错误:

# vi /var/log/messages
...
Nov  8 08:54:58 server kernel: ip_conntrack: table full, dropping packet.
Nov  8 08:55:03 server kernel: printk: 49 messages suppressed.
Nov  8 08:55:03 server kernel: ip_conntrack: table full, dropping packet.
Nov  8 08:55:08 server kernel: printk: 49 messages suppressed.
...

查看当前 ip_conntrack 记录,已经有 36271,超过了系统设置的 16640 (ip_conntrack_max 默认设置为系统内存(MB 为单位)的 16倍):

$ head /proc/slabinfo 
slabinfo - version: 2.1
# name                 : tunables    : slabdata   
ip_conntrack_expect      0      0    192   20    1 : tunables  120   60    8 : slabdata      0      0      0
ip_conntrack        36271  36216    384   10    1 : tunables   54   27    8 : slabdata   1612   1612    108

# cat /proc/sys/net/ipv4/ip_conntrack_max
16640

kernel 用 ip_conntrack 模块来记录 iptables 网络包的状态,并保存到 table 里(这个 table 在内存里),如果网络状况繁忙,比如高连接,高并发连接等会导致逐步占用这个 table 可用空间,一般这个 table 很大不容易占满并且可以自己清理,table 的记录会一直呆在 table 里占用空间直到源 IP 发一个 RST 包,但是如果出现被攻击、错误的网络配置、有问题的路由/路由器、有问题的网卡等情况的时候,就会导致源 IP 发的这个 RST 包收不到,这样就积累在 table 里,越积累越多直到占满,满了以后 iptables 就会丢包,出现外部无法连接服务器的情况。

知道问题就好办了,要么增加 table 容量以便能记录更多的连接信息(会消耗一点内存),要么就卸载 ip_conntrack 模块。

查看当前 ip_conntrack_max 设置,然后增加两倍到 131072:

# cat /proc/sys/net/ipv4/ip_conntrack_max
16640

# echo 131072 > /proc/sys/net/ipv4/ip_conntrack_max
或者
# sysctl -w  net.ipv4.netfilter.ip_conntrack_max=131072

还有一个参数 ip_conntrack_tcp_timeout_established 需要注意,默认情况下 timeout 是5天(432000秒),需要的话可以减半:

# cat /proc/sys/net/ipv4/netfilter/ip_conntrack_tcp_timeout_established 
432000

# sysctl -w net.ipv4.netfilter.ip_conntrack_tcp_timeout_established=216000
net.ipv4.netfilter.ip_conntrack_tcp_timeout_established = 216000

综合一下,最好把这些内核参数加到 sysctl.conf 文件以便系统启动后自动读取中:

# vi /etc/sysctl.conf
...
net.ipv4.netfilter.ip_conntrack_max = 131072
net.nf_conntrack_max = 131072
net.ipv4.netfilter.ip_conntrack_tcp_timeout_established = 216000

还有一种办法就是直接卸载 ip_conntrack 模块,这个办法最简单,到在 /etc/sysconfig/iptables-config 文件里删除或者注释掉 ip_conntrack_netbios_ns 后重启系统:

# vi /etc/sysconfig/iptables-config
#IPTABLES_MODULES="ip_conntrack_netbios_ns"

# shutdown -r now