mysql中操作事务时要注意的事项

操作事务是个很普遍的过程,凡时对数据库的修改有相互依赖都应该使用事务解决。操作事务时要注意以下几点:

1、尽量使用Exception捕获MYSQL的异常

所以第一步:要设置PDO的异常模式为PDO::ERRMODE_EXCEPTION,PDO::ATTR_ERRMODE,有以下三个值:

  • PDO::ERRMODE_SILENT: 默认模式,不主动报错,需要主动以 $pdo->errorInfo()的形式获取错误信息。
  • PDO::ERRMODE_WARNING: 引发 E_WARNING 错误,主动报错
  • PDO::ERRMODE_EXCEPTION: 主动抛出 exceptions 异常,需要以try{}cath(){}输出错误信息。

我们在连接MYSQL时使用以下:

$pdo=new pdo("mysql:host=localhost;dbname=dbname","user","****", array(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION));

将上面这句代码写在try catch中,捕获异常,注意PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION必须写在new pdo中。不然mysql连接错误的信息是捕获不到的。catch中的类限制为PDOException,如果有命名空间注意在前面加上顶级命名空间,不然也捕获不了异常的。

2、MYSQL的事务开始前先关闭AUTOCOMMIT

$pdo->setAttribute(PDO::ATTR_AUTOCOMMIT, 0);
$rs = $pdo->beginTransaction();

注意beginTransaction是有返回值的,在调用事务beginTransaction时最好判断其返回值,如果本身返回为false,则后面就不用再回滚。

3、操作事务及回滚

切记在所有的return之前或者其它结束事务之前都记得调用rollBack方法,rollBack方法中也是有返回值的,最好判断返回值,并重试2次回滚,以防止一次回滚发生异常,导致事务锁住。

4、执行开启自动提交

$pdo->setAttribute(PDO::ATTR_AUTOCOMMIT, 1);

此步非常关键,不管是执行commit还是执行rollBack都务必执行此步,自动提交的意义是你执行的每一句SQL是否直接执行MYSQL.默认的MYSQL就是自动提交的,即你执行一条SQL语句,它就更改到数据库,如果MYSQL不是自动提交,则你执行的MYSQL语句就全部卡在那里等待执行。

事务出现异常时最常出现的现象就是前端浏览器涉及到被锁表或行的请求都处在等待中,最后可能报错mysql innodb Lock wait timeout exceeded; try restarting transaction问题,此时:

第一:可通过SHOW ENGINE INNODB STATUSG;查询报错信息,这个信息量太大了,不好排查。

第二:使用select * from information_schema.innodb_trx G; 查询运行的任务列表。

mysql> select * from information_schema.innodb_trx G;                  
*************************** 1. row ***************************
                    trx_id: 1429E713A
                 trx_state: RUNNING
               trx_started: 2018-04-02 16:25:31
     trx_requested_lock_id: NULL
          trx_wait_started: NULL
                trx_weight: 0
       trx_mysql_thread_id: 23698460
                 trx_query: NULL
       trx_operation_state: NULL
         trx_tables_in_use: 0
         trx_tables_locked: 0
          trx_lock_structs: 0
     trx_lock_memory_bytes: 376
           trx_rows_locked: 0
         trx_rows_modified: 0
   trx_concurrency_tickets: 0
       trx_isolation_level: REPEATABLE READ
         trx_unique_checks: 1
    trx_foreign_key_checks: 1
trx_last_foreign_key_error: NULL
 trx_adaptive_hash_latched: 0
 trx_adaptive_hash_timeout: 10000
mysql> select trx_id,trx_started,trx_state,trx_mysql_thread_id,trx_rows_locked from information_schema.innodb_trx;     
+-----------+---------------------+-----------+---------------------+-----------------+
| trx_id    | trx_started         | trx_state | trx_mysql_thread_id | trx_rows_locked |
+-----------+---------------------+-----------+---------------------+-----------------+
| 1429E713A | 2018-04-02 16:25:31 | RUNNING   |            23698460 |               0 |
| 1429E7138 | 2018-04-02 16:25:31 | RUNNING   |            23698458 |               0 |
| 1429E7136 | 2018-04-02 16:25:31 | RUNNING   |            23697458 |               0 |
| 1429E6734 | 2018-04-02 16:14:39 | RUNNING   |            23698477 |               1 |
+-----------+---------------------+-----------+---------------------+-----------------+
4 rows in set (0.00 sec)
#可以通过trx_mysql_thread_id值查询processlist查看导致异常的mysql连接
select * from information_schema.processlist where db='dbname' and id =23698477;

第三,可以排查mysql的bin日志:MYSQL日志文件: show variables like general_log_file;

mysql>  show variables like 'general_log_file';
+------------------+-------------------------------+
| Variable_name    | Value                         |
+------------------+-------------------------------+
| general_log_file | /opt/data/mysql/localhost.log |
+------------------+-------------------------------+
1 row in set (0.00 sec)

找到日志文件,直接查看binlog文件可能有乱码。

/opt/modules/mysql/bin/mysqlbinlog --base64-output=DECODE-ROWS  mysql-bin.000098

但上面的这个命令只能将已有的日志文件解码展示,不区分里面的数据库,如果日志文件很大,就歇菜了。下面的命令可以指定数据库开始时间:

/opt/modules/mysql/bin/mysqlbinlog --start-datetime='2018-04-02 10:25:00' -d baotoutiao mysql-bin.000098

但上面的命令都不够好,下面这个最佳。可以实现模拟tail -f的功能。并且可指定数据库,非常好用。

export D=$(date +"%Y-%m-%d %H:%M:%S" --date="1 minutes ago"); watch "/opt/modules/mysql/bin/mysqlbinlog --start-datetime="$D" -d dbname --base64-output=decode-rows -v mysql-bin.000098|tail -n 50"

使用rsync定时远程同步

一般场景下,通过rsync可以结合crontab实现按时自动备份,在远程自动同步的场景下,rsync 需要以守护进程的方式来运行,本文记录实现异地自动备份的过程。

生产服务器主机A的地址:192.168.214.190 :centos7.4

备份数据主机B的地址:192.168.214.187 :centos6.9

客户端和服务端都要安装rsync,安装完后有些系统不会生成rsyncd.conf,需要自己创建在 /etc/rsync.d/rsyncd.conf

【在centos7.4上安装rsync会默认生成/etc/rsyncd.conf文件,但是在centos6.9上安装后则不会生成,并且,如果在要自己定义文件位置,以守护进程方式启动,那么任然要在/etc/下新建一个rsyncd.conf的文件,否则无法启动。】

服务端安装rsync:

[root@localhost ~]#yum install rsync -y

创建配置文件

[root@yufu ~]# mkdir -p /etc/rsync.d
[root@yufu ~]# touch /etc/rsync.d/rsyncd.conf
[root@yufu ~]# chmod 600 /etc/rsync.d/rsync.conf

编辑配置文件内容

vim /etc/rsync.d/rsyncd.conf

log file = /var/log/rsyncd.log
pid file = /var/run/rsyncd.pid
lock file = /var/run/rsync.lock

[bak]
path=/opt/server
uid = root
gid = root
ignore = errors
read only = no
write only = no
host allow = *
max connections = 5
host deny = 192.168.22.21
list = false
auth users = feng
secrets file = /etc/rsync.d/server.pass

添加备份用户的用户密码文件,并修改文件权限

echo 'filebak:filebak' > /etc/rsync.d/server.pass
chmod 600 server.pass

服务端的rsync安装配置好后就可启动了,rsync是以守护进程的方式启动:

[root@localhost ~]#rsync --daemon --config=/etc/rsync.d/rsyncd.conf 

[root@localhost ~]#ps -ef | grep rsync
root      2356     1  0 17:29 ?        00:00:00 rsync --daemon --config=/etc/rsync.d/rsyncd.conf
root      2361  1965  0 17:29 pts/1    00:00:00 grep --color=auto rsync

到此服务端的的设置完成,接着安装客户端,在备份主机上不用做任何设置,只要安装rsync服务和设置crontab任务计划就可以, 为了在同步的过程中不用输入密码,因此需要在备份主机上创建一个secrets 文件,该文件内容是服务端的rsyncd.conf中“auth users”指定的用户的密码;这个文件名和路径随意指定,只要在执行同步指令时指定即可。

安装rsync

yum install rsync -y

向客户端添加同步用户的密码

[root@yufu ~]# echo 'fsz...' > /etc/rsync.d/feng.pass

[root@yufu ~]# chmod 600 /etc/rsync.d/feng.pass 

在客户端执行同步

[root@yufu ~]# rsync -arzvtopg --delete [email protected]::bak /opt/app/ --password-file=/etc/rsync.d/feng.pass 
rsync: failed to connect to 192.168.214.190: No route to host (113)
rsync error: error in socket IO (code 10) at clientserver.c(124) [receiver=3.0.6]

执行报错:原因是服务端的防火墙没有放行策略,关闭防火墙;

[root@localhost ~]#systemctl stop firewalld

再执行:

[root@yufu ~]# rsync -arzvtopg --delete [email protected]::bak /opt/app/ --password-file=/etc/rsync.d/feng.pass 
receiving incremental file list
./
install-lnmp.sh

sent 75 bytes  received 1410 bytes  990.00 bytes/sec
total size is 3522  speedup is 2.37
[root@yufu ~]# cd /opt/app/ && tree
.
└── install-lnmp.sh

0 directories, 1 file
[root@yufu app]# ls
install-lnmp.sh

客户端设置定时备份:添加crontab任务计划,每天定时同步文件

[root@yufu ~]# crontab -l
*/1 * * * * /usr/bin/rsync -arzvtopg --delete [email protected]::bak /opt/app/ --password-file=/etc/rsync.d/feng.pass
设置定时同步,作为测试,设置每分钟同步一次

服务端测试文件更新脚本

#!/bin/bash
dir=/opt/server
cd $dir
for i in $(seq 1 10)
do
touch file$i
sleep 61
done

测试脚本执行结束后再查看服务端和客户端的目录情况

[root@yufu app]# ls   #客户端
file1  file10  file2  file3  file4  file5  file6  file7  file8  file9  install-lnmp.sh  tess


[root@localhost server]#ls  #服务端
file1  file10  file2  file3  file4  file5  file6  file7  file8  file9  install-lnmp.sh  tess

MySQL下perror工具查看System Error Code信息

在MySQL数据库的维护过程中,我们有时候会在MySQL的错误日志文件中看到一些关于Operating system error的错误信息,例如在MySQL的错误日志里面,有时候会看到关于

InnoDB: Operating system error number 0.
InnoDB: Check that your OS and file system support files of this size.
InnoDB: Check also that the disk is not full or a disk quota exceeded.


InnoDB: Operating system error number 5.
...........................................

那么这些System Error Code在Linux下分别代表什么意思呢?其实如果遇到错误日志里有这些对应的代码,使用MySQL自带的命令工具perror查看一下具体信息即可。非常简单方便。

[root@DB-Server ~]# perror 2;
OS error code   2:  No such file or directory
[root@DB-Server ~]# perror 3;
OS error code   3:  No such process
[root@DB-Server ~]# perror 4;
OS error code   4:  Interrupted system call
[root@DB-Server ~]# perror 5;
OS error code   5:  Input/output error
[root@DB-Server ~]#

如果你要查看一个范围的Operating system error,可以使用下面命令

[root@DB-Server ~]# perror `seq 0 10`
OS error code   0:  Success
OS error code   1:  Operation not permitted
OS error code   2:  No such file or directory
OS error code   3:  No such process
OS error code   4:  Interrupted system call
OS error code   5:  Input/output error
OS error code   6:  No such device or address
OS error code   7:  Argument list too long
OS error code   8:  Exec format error
OS error code   9:  Bad file descriptor
OS error code  10:  No child processes
[root@DB-Server ~]#

如果是集群,那么可以shell> perror –ndb errorcode查看, 下面表格是关于Linux平台下通用的System Error Code列表,如下所示,完全没有必要硬性记住。遇到查看即可。

未分类

如果是Windows平台,那么也可以使用下面命令查看具体的System Error Code信息,另外,Windows平台下的System Error Code也远比Linux平台下要多,遇到了这些System Error Code,使用命令查看即可。

perror.exe 2


perror `perl -e "print join ' ',1..100"`

Linux系统下安装nfs并配置iptables

服务端安装

系统环境(Centos6.x)
nfs服务器IP:192.168.137.10
nfs客户端IP:192.168.137.11

1. 安装NFS

yum install -y nfs-utils
vim /etc/exports   ##nfs配置文件,写入如下信息
/home/ 192.168.137.0/24(rw,sync,all_squash,anonuid=501,anongid=501)

注:如上信息分为三部分,第一部分就是本地要共享出去的目录,第二部分为允许访问的主机(可以是一个IP也可以是一个IP段)第三部分就是小括号里面的,为一些权限选项。它表示:共享的目录为/home,信任的主机为192.168.137.0/24这个网段,权限为读写,同步,限定所有使用者,并且限定的uid和gid都为501。

2. NFS相关配置选项

未分类

3. 启动服务

service rpcbind start
service nfs start             ##成功启动的条件是防火墙没有做设置或者未开启。

客户端挂载NFS

yum install -y nfs-utils
#查看服务器端都共享了哪些目录 
showmount -e 192.168.137.10
/home 192.168.137.0/24(rw,sync,all_squash,anonuid=501,anongid=501)
#挂载
mount -t nfs -o nolock 192.168.137.10:/home /mnt
#查看挂载的情况
df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda3        28G  1.5G   25G   6% /
tmpfs           1.9G     0  1.9G   0% /dev/shm
/dev/sda1       194M   27M  158M  15% /boot
/home           480G   10G  470G  47% /mnt

iptables设置

以上nfs服务端和客户端能正常使用的前提是系统没设置防火墙,或者未开启iptables.
实际在生产环境下,为了系统和业务的安全性我们都有设置防火墙。那么需要添加iptables的端口。

vim /etc/sysconfig/nfs        #指定以下的端口号

RQUOTAD_PORT=10001
LOCKD_TCPPORT=10002
LOCKD_UDPPORT=10003
MOUNTD_PORT=10004
STATD_PORT=10005

查看当前这5个服务的端口并记录下来:

rpcinfo -p    #nfs  2049, portmapper  111, 将剩下的三个服务的端口随便选择一个记录下来

添加iptables设置:

iptables -A INPUT -p tcp --dport 111 -j ACCEPT
iptables -A INPUT -p udp --dport 111 -j ACCEPT
iptables -A INPUT -p tcp --dport 2049 -j ACCEPT
iptables -A INPUT -p udp --dport 2049 -j ACCEPT
iptables -A INPUT -p tcp --dport 10001:10005 -j ACCEPT
iptables -A INPUT -p udp --dport 10001:10005 -j ACCEPT
service iptables save
service iptables restart

重启服务:

service rpcbind restart
service nfs restart

linux MariaDB(MySQL)数据库更改用户权限

平时维护MariaDB(MySQL)数据库服务器,难免会用到一些常用的命令,MariaDB数据库长时间不出问题,有些sql语句就会忘记,之前也没有记载,今天没事就记录下,也共享给大家一块看看,有不足之处还望谅解。

本文操作适用于MariaDB所有版本,适用于MySQL5.2以上版本
本文生产环境Centos7.3 64位 ,MariaDB server 10.2.5

MariaDB 赋予用户权限命令的简单格式可概括为:

grant 权限 on 数据库对象 to 用户;

# mysql -u root -p //登录数据库
 Enter password:
 MariaDB [(none)]> show databases; //查看当前数据库中所有数据库
 MariaDB [(none)]> create database renwole; //新建数据库名为“renwole”
 MariaDB [renwoleBD]> show tables; //显示某个数据库中的表文件
 MariaDB [(none)]> select version(),current_date; //查看数据库版本和当前日期
 MariaDB [(none)]> drop database renwole; //删除renwole数据库
 MariaDB [renwoleDB]> desc 表名称; //查看数据库表结构
 MariaDB [(none)]> show variables like '%dir%'; //查看数据库存储路径
 MariaDB [(none)]> show grants; 查看当前用户权限
 MariaDB [(none)]> show grants for root@'localhost'; //查看用户权限

下面就MariaDB数据库实例讲解,例如:

创建添加一个renwole用户,密码为renwole123

# mysql -u root -p //登录数据库
 Enter password:
 MariaDB [(none)]> insert into mysql.user(Host,User,Password) values("localhost","renwole",password("renwole123"));

新建一个renwoleDB数据库,并授权用户renwole拥有该数据库的所有权限。

MariaDB [(none)]> create database renwoleDB; //新建
 MariaDB [(none)]> grant all privileges on renwoleDB.* to renwole@% identified by 'renwole123'; //授权,关键字 “privileges” 可以省略。
 MariaDB [(none)]> flush privileges; //刷新用户权限

如果想给一个用户查询、插入、更新、删除数据库中的所有表数据权利,可以这样来写:

MariaDB [(none)]> grant select on on renwoleDB.* to renwole@’%’ //查询
 MariaDB [(none)]> grant insert on on renwoleDB.* to renwole@’%’ //插入
 MariaDB [(none)]> grant update on on renwoleDB.* to renwole@’%’ //更新
 MariaDB [(none)]> grant delete on on renwoleDB.* to renwole@’%’ //删除

或者,用一个语句命令替代:

MariaDB [(none)]> grant select,insert,delete,update on renwoleDB.* to renwole@’%’ identified by 'renwole123';

如果想查看所有Mysql用户的权限,代码如下;

MariaDB [(none)]> SELECT DISTINCT CONCAT('User: ''',user,'''@''',host,''';') AS query FROM mysql.user;

如果想删除一个用户及权限,可以这样写;

MariaDB [(none)]> drop user renwole@localhost;

如果想修改一个用户密码;

MariaDB [(none)]> update mysql.user set password=password('New-password') where User="renwole" and Host="%";
 MariaDB [(none)]> flush privileges;

添加高级root用户整个mysql服务器权限

grant all on *.* to root@'%' identified by 'Password';

注意:【identified by】这个句子可以顺带设置密码,如果不指定该用户口令不变。

撤销已经赋予给MariaDB用户的权限。
revoke 跟 grant 的语法相似,只需要把关键字 “to” 换成 “from” 即可,例如:

grant all on *.* to renwole@%;
revoke all on *.* from renwole@%;

MariaDB数据库的 grant、revoke 用户权限注意事项;grant, revoke 用户权限后,该用户只有重新连接 MySQL 数据库,权限才能生效。如果想让授权的用户,也可以将这些权限 grant 给其他用户,需要选项 “grant option“,例如:

MariaDB [(none)]> grant select on renwoleDB.* to renwole@% with grant option;

这个特性一般用不到。实际中,数据库权限最好由root用户来统一管理。

注意:有时候renwole@’%’授权任意主机连接的时候需要加单引号,但有时又不需要。

Kubernetes监控系列(四):Docker + Kubernetes在WayBlazer的使用案例

【编者的话】本文是关于在生产中使用Kubernetes系列的一部分。第一部分介绍了Kubernetes和监控工具的基础知识;第二部分涵盖了Kubernetes报警的最佳实践;第三部分对Kubernetes故障排除,特别是服务发现进行了介绍,最后一部分是监控Kubernetes的实际使用案例。

将Docker引入生产环境,既是一门科学,同时也是一门艺术。我们与WayBlazer的Kevin Kuhl和Kevin Cashman一起讨论有关Docker和Kubernetes的监控、选择正确的关注指标、决定使用Kubernetes来运行何种程序以及诊断Kubernetes故障转移中的“多米诺效应”。

Update:在写完这篇文章的一年后,我们与Wayblazer的Kevin Kuhl、Kevin Cashman再次进行了讨论,并在他们的Kubernetes部署安全性方面增加了一些新的有洞察力的细节。

WayBlazer介绍

WayBlazer是世界上第一个专注于向旅游行业提供人工智能技术的认知推荐引擎。结合IBM Watson和专有认知计算技术,WayBlazer的AI技术对旅行者搜索历史提供的线索进行分析,以便为他们的旅行提供个性化的酒店推荐、见解、图像和当地文化。个性化内容与酒店推荐相结合可提高在线参与度并提高旅行者转化率。

该公司总部位于得克萨斯州奥斯汀,由经验丰富的旅游、科技企业家领导,其中包括Travelocity的创始人/ Kayak.com的创始人主席,IBM前任总经理Watson,以及Sabre Hospitality Solutions的前总裁。

你的环境是什么样的?

我们是一家AWS商店,所以可以想象我们会大量使用EC2。 同时我们还使用了许多AWS服务,这些服务易于使用,价格可取,而且管理得很好。 这些都能使我们的生活变得更轻松。 不久之前,我们开始使用Kubernetes,现在我们在EC2节点之上运行了十几个Kubernetes工作节点(有时甚至更多)。 每个节点运行约15-20个容器。 另外,我们有许多Kubernetes命名空间,如prod、test以及project-specific。

在上述环境中,我们运行了许多不同的服务。 我们的前端是JavaScript,API服务在Node.js上运行。 同时Java服务处理主要逻辑,还有一些在Python中运行的辅助应用程序。

我们使用Sysdig Monitor和AWS Cloudwatch来监控集群。我们依靠许多Kubernetes和AWS平台功能来保护集群内的应用程序,但同时也开始使用Sysdig Secure来加强集群的运行时防御能力。

你在Kubernetes内运行一切应用吗?

不是的。 我们的方法是首先说“它应该在Kubernetes中运行吗?”,但在有些领域,我们的答案是否定的。 不在Kubernetes中运行的应用,要么是功能需求不匹配,要么是性能达不到要求。

最显而易见的,我们的无状态服务通常运行在Kubernetes中,这简直是个完美的选择。 然而有状态的服务,例如图形数据库,还不是很适合。 也许使用PetSets最终能够做到这一点,但现在不行。 最后,我们的批处理作业或者定时作业通常不会运行在Kubernetes上。 同样,这是Kubernetes正在发展的方向,但现在不能满足我们的需求。

从安全和访问的角度来看,Docker,AWS,Kubernetes和其他服务都需要监控,而且从应用程序性能角度来看也是如此。 是如何做到同时监控这一切呢?

我们先谈谈平台安全保护。 从一开始我们使用kubernetes TLS——这能控制对kube-ctl的访问。 从网络角度来看,Amazon ELB是安全的,并可以保护应用程序免于暴露于外。 这对集群免于外力攻击非常给力。 然而,这些工具无法保证集群内没有发生任何不利事件。接下来当我们深入讨论Sysdig Secure时会再谈这个问题。

从传统的监控角度来看,我们仅依靠AWS Cloudwatch提供的主机级监控。 这在使用Docker和Kubernetes,也就是更静态的体系架构之前是没有问题的。 而且,相对静态的体系架构下,可以从基础设施的监控信息中获得关于应用程序性能的更多信息。 迁移到Kubernetes后发生了改变, 我们需要在容器和服务级别进行监控。

Kubernetes默认提供Heapster和Grafana,这是我们的第一次尝试。 为了使用和管理这些组件,我们投入了大量的时间和努力。 鉴于我们是由两人组成的运维团队,这显然不是值得我们投入大量时间的方式。 我们需要一个功能全面,健壮监控功能,并且易于开展工作的监控工具。

所以对于我们来说,这排除了自己组合组件的方式。 我们最终选择了符合需求的商业产品。 实际上,我们仍然使用CloudWatch监控基本的AWS指标,同时使用Sysdig用于更高级别的内容。 尽管在监控底层基础设施方面存在一些重复,但没有任何影响。

Kubernetes是否会影响Docker的监控? 并保护它?

是的,但Kubernetes影响很多方面,而不仅仅是监控。 如果我们回到为什么选Kubernetes这一问题上,一方面是它能精确地描述它在做什么,并且有它自己的语言来描述它:namespace,deployment等等。 这种“语言”统一了容器技术的使用方式。 这使得与工程师,运维人员或者任何参与到软件开发过程的人员的交流变得容易。

为了获取更加具体的监控信息,到目前为止,迁移到Kubernetes最重要,最明显的原因是对深入了解以Kubernetes为中心和以服务为中心的代码视图。实际上,很多软件可以通过与Docker API交互来监控基础设施级别的Docker容器,但他们不知道容器的具体信息。了解构成API服务的容器组,或者某个容器是某个Pod/ReplicaSet的一部分是非常有价值的,这使我们重新定义了对监控的需求。

对安全性有类似的思路:一个从以服务、Kubernetes为中心角度,且可以了解容器内部所发生事情的安全工具,比只通过镜像名区分容器或容器组的工具强大得多。

好吧,既然我们正在和你一起写这篇文章,我们都可以十分肯定地假设WayBlazer选择了Sysdig。 为什么?

是的。 我们现在使用了整个Sysdig容器智能平台——Sysdig Monitor,Sysdig Secure和开源故障排除工具。 Sysdig是一个优秀的集成基础设施监控、Kubernetes集群监控的工具。 基本上没有其他工具具有如此能力,通常我们都需要这两部分的监控才能在生产环境中运行容器。

Sysdig加强了Kubernetes的语言通用性。 它了解Kubernetes的基本结构。 不需要告诉Sysdig任何信息,也不必去适应它。 一旦部署了Sysdig,就可以获得想要的服务级别的指标信息,命令历史记录以及安全策略违规记录。

所有这些都来自一个统一的Agent。 在添加Sysdig Secure之前,Sysdig Monitor已经运行了大约18个月,我们只需添加一个额外的conf变量到Sysdig agent YAML文件中,Kubernetes Daemonset便会负责剩下的事情。

另外重要的一点是Sysdig可以获得容器内部更多的应用程序或以代码为中心的应用程序视图。 虽然我们十分关注基础架构指标,但同时也关注应用程序的监控信息。 Sysdig可以做到开箱即用,甚至当Kubernetes正在对Docker容器进行扩缩容。

所有这些方面都降低了成本,也提升了我们的效率。 这意味着我们不必为了将Kubernetes元数据转换成衡量指标而花费精力,也不必过多考虑如何使用我们的系统。

一旦应用程序部署在生产环境中,该如何保护呢?

上文已经提到了平台能提供安全性。 但是,我们仍然需要一些能够为运行时行为提供安全性的服务。 这些行为可能发生在主机级别,应用程序级别或系统中其他任何地方。 我欣赏Sysdig Secure,因为除了拥有以服务为中心的策略来提醒或阻止行为之外,还能让我们深入了解系统内发生的所有事情。 明确没有发生的事情的确能使人安心很多。

运行时安全最让人担心的问题是(1)谁在登录系统,他们在做什么;(2)是否有人正在修改系统内重要的文件? Sysdig安全策略默认已经对登录,远程shell连接,未经授权的连接以及其他一些行为进行了防御和提醒,所以只需要为自定义应用程序创建一些特定的策略。 我们需要更高的优先级和更严格定义的安全策略。

就上文所描述的可见性,Secure提供历史命令查看就是一个很好的例子。 它提供查看系统中所执行的一切内容的能力,从微服务、到主机或容器等等,总之,一切我想看的内容。 另外,Sysdig Monitor的另一功能是可以及时查看指标信息,这也非常有用。 现在,如果将这两者结合在一起会非常有用。 如果在监控页面(显示内存,响应时间信息等)中看到不正常信息或事件,便可以回到命令历史记录获得更多信息,如是否有人在该服务或容器上运行了新的东西?

让我们更深入一点。 什么是最重要的监控指标? 你一天到晚最想知道什么?

有趣的是,我们正在讨论Docker监控,但却没有真正地监控Docker。而是专注于监控应用程序,并在某种程度上监控Kubernetes以向我们提供有关应用程序运行的环境信息。 我们经常使用Docker相关信息进行故障排除,这是我们基础架构栈中的另一个层面,并且可能经常提供帮助我们解决棘手问题的信息。 以下是我们在应用程序级别监控的一些关键内容:

  • 请求时间:我们密切关注前端和API的请求和响应时间。如果出现问题或变化,这些是需要首先关注的指标。 例如,一次新构建可能会导致应用程序执行失败,或者,一次网络配置错误可能会对用户产生负面影响。
  • 后端查询响应时间:这些可能直接与数据库或Java后端相关。 当然,这是寻找潜在问题的好地方,也是改善系统的机会。 如果通常情况下,查询运行缓慢,便可以将其返回给团队进行研究和修复。
  • 堆使用和垃圾回收:虽然不经常使用,但我们已经使用这些数据来调试基于JVM级数据的数据仓库。 从应用程序级别来看,我们确实需要关注这些资源指标。

接下来是Kubernetes。 以下是我们关注的内容:

  • Pod重启和容器计数:告诉我们是否有变化发生。
  • 启动失败:这些是可以用来关联其他指标的重要事件,无论是应用还是基础架构。
  • 服务请求延迟:这一点极具挑战。 它涉及汇总来自特定服务的所有容器的延迟信息,并以一个统一的视图呈现。 这是在监控中使用“Kubernetes视点”的最佳例子。
  • 容器平均资源利用率:我们最近在Kubernetes中添加了资源请求和限制机制,这意味着我们可以更有效地追踪资源利用率。 相比根据主机级别CPU和内存信息来监控资源利用率,我们选择根据分配给特定容器的资源来进行监控。 这能在资源分配问题上更早的提示警告,而不是仅仅在主机利用率级别进行监控。

关键节点上高CPU、内存和磁盘使用率,我们已经有了报警机制。 你也需要这些功能。

能谈谈你监控Kubernetes“多米诺骨牌效应”的故事吗?

这是我们在EC2中运行Kubernetes时早就经历的一件事。 我们的第一个警告指标是API高延迟的警报。 但此时延迟时间开始降低,虽然我们已准备好在必要时采取行动,但系统似乎稳定了。

但很快我们明白了问题的严重性。 我们看到了Kubernetes管理的节点缩容的警报。 我们立即查看了Sysdig,注意到蓝线在下降。 这不太好,但事情还没有结束。 Kubernetes正在干掉相关容器,并移到另一个节点。

未分类

然后同时看到磁盘和内存使用率都非常高。 这是最后的警告。 然后整个系统崩溃了。

未分类

基本上这就是多米诺骨牌效应——Kubernetes对第一个节点做了failvoer,它在内存耗尽时清除了所有容器。 此时,某些服务上并不存在对内存使用的请求和限制。

未分类

问题在于集群中的其他节点的磁盘使用已经比较高了,以至于无法为需要迁移的容器保留足够的空间。

未分类

我们很快就能够扩大自动伸缩组并修复一些节点,让系统恢复正常。 但这通常来说比较痛苦,而且很不理想。在之后对此的回顾汇总,我们很有趣的发现,能够通过Sysdig查看到整个事情。 然后在一天内与团队一起发布了一个可靠的关于系统行为的报告。 同时我们整理了一份完整的操作列表,其中有在系统达到特定阈值、限制条件、扩容策略等的具体操作。 这使我们的系统更加健壮。

你能总结一下在Docker监控方面的经验教训吗?

我们的经验表明,采用Kubernetes和Docker会对监控方法产生很大影响。 就像Kubernetes使我们可以从一个更加service-centric的视角来对待整个基础设置,监控策略也会以同样的方式发生变化。

你需要在监控系统中使用基于基础架构的视图(监控的标准方式)和以服务为中心的视图(监控的新方法),以在生产环境中运行容器。

确保你的监控系统能够强化Kubernetes的语言通用性。 它必须了解Kubernetes开箱即用的基本结构。 而且你不应该告诉他任何信息。 一旦部署,就可以获得服务级别的监控信息。

另外重要的一点你的工具应该在容器中看到更多的应用程序信息或以代码为中心的应用程序视图。 尽管我们密切关注基础架构指标,但我们仍然专注于监控应用程序,不管Kubernetes正在启动或停止Docker容器。

所有这些方面都降低了成本,也提升了我们的效率。 这意味着我们不必为了将Kubernetes元数据转换成衡量指标而花费精力,也不必过多考虑如何使用我们的系统。

希望你喜欢Kubernetes监控这一系列文章! 如果你想了解更多,下面我们的首席执行官和创始人Loris Degioanni在CloudNativeCon / KubeCon “You’re Monitoring Kubernetes Wrong”的演讲。

视频: https://v.qq.com/x/page/c0603u1t44l.html

Kubernetes监控系列(三):Kubernetes服务发现与故障排除

【编者的话】本文是Kubernetes监控系列的第三篇,主要讲述了Kubernetes的故障排除以及服务发现。

本文是关于在生产中使用Kubernetes系列的一部分。第一部分介绍了Kubernetes和监控工具的基础知识;第二部分涵盖了Kubernetes报警的最佳实践。这部分将介绍对Kubernetes故障排除,特别是服务发现,最后一部分是监控Kubernetes的实际使用案例。像Kubernetes,DC / OS Mesos或Docker Swarm这样的容器编排平台可以帮助你方便地管理容器,但对解决容器问题并没有什么帮助:

  • 它们是孤立的,你和你要监视的进程之间存在一定的障碍,在主机上运行的传统故障排除工具不了解容器、命名空间和编排平台。
  • 它们带来最小的运行时间,只需要服务及其依赖项,而不需要所有的故障排除工具,想象下只用busybox来进行故障排除!
  • 它们调度在你集群、进行容器移动,扩容或者缩容。随着流程的结束,它们变得非常不稳定,出现并消失。
  • 并通过新的虚拟网络层互相通信。

本文将通过一个真实用例讲诉如何在Kubernetes中进行故障排除。我们将涵盖Kubernetes内部3个不同层的故障排除:

  • 第一部分:Kubernetes故障排除之服务发现
  • 第二部分:Kubernetes故障排除之DNS解析
  • 第三部分:Kubernetes故障排除之使用Docker运行容器

本文场景将使用一个简单的Kubernetes服务,包括3个Nginx pod和一个带有curl命令的客户端。在链接中可以看到场景需要使用的yaml文件 backend.yaml。如果你刚刚接触Kubernetes,可以看下“Understanding how Kubernetes DNS services work”这篇文章来学习如何部署上述服务。实际操作如下:

$ kubectl create namespace critical-app
namespace "critical-app" created
$ kubectl create -f backend.yaml
service "backend" created
deployment "backend" created

然后创建一个客户端来加载我们的后端服务:

$ kubectl run -it --image=tutum/curl client --namespace critical-app --restart=Never

第一部分:Kubernetes故障排除之服务发现

在我们的client容器中可以运行一个简单测试 root@client:/# curl backend 来查看我们的Kubernetes service是如何工作的。但我们不想遗漏下什么,我们认为可以使用FQDN进行服务发现测试,在Kubernetes文档中会发现,每个service都会获得一个默认的DNS:my-svc.my-namespace.svc.cluster.local。因此,我们用它作为FQDN进行测试。

在client容器的shell端运行:root@client:/# curl backend.critical-app.svc.cluster.local,不过这次curl命令卡住了10秒,然后返回了预期网址!作为一个分布式系统工程师,这是最糟糕的事情之一:你希望直接失败或者成功,而不是等待10秒。

为了定位出问题,我们使用了Sysdig。Sysdig是一个开源Linux可视化工具,提供对容器的本地可见性,包括Docker、Kubernetes、DC / OS和Mesos等等。将htop,tcpdump,strace,lsof,netstat等的功能组合在一起,Sysdig提供了Kubernetes基础架构环境中的所有系统调用和应用程序数据。Monitoring Kubernetes with Sysdig中很好地介绍了如何在Kubernetes中使用这个工具。

为了分析上述问题原因,我们将请求sysdig来dump所有信息到捕获文件中:

$ sudo sysdig -k http://127.0.0.1:8080 -s8192 -zw capture.scap

快速解释下每个参数:

  • -k http://localhost:8080 连接Kubernetes API
  • -s8192 扩大IO缓冲区,因为我们需要显示全部内容,否则默认情况下会被切断,
  • -zw capture.scap 将系统调用与元数据信息压缩并dump到文件中

同时,我们将再次运行curl命令来复现这个问题:# curl backend.critical-app.svc.cluster.local。这确保了我们在上面捕获的文件中拥有所有数据,以重现场景并解决问题。

一旦curl返回,我们可以执行Ctrl+C来终止数据捕获,并且我们将拥有一个10s的捕获文件,包括我们的Kubernetes主机中发生的所有事情以及服务发现过程。现在我们可以开始在集群内或集群外解决问题,只要在安装了sysdig的环境中复制文件:

$ sysdig -r capture.scap -pk -NA "fd.type in (ipv4, ipv6) and (k8s.ns.name=critical-app or proc.name=skydns)" | less

快速解释下每个参数:

  • -r capture.scap 读取捕获文件
  • -pk 打印Kubernetes部分到stdout中
  • -NA 显示ASCII输出

以及双引号中是过滤内容。Sysdig能够理解Kubernetes语义,因此我们可以过滤来自名称空间critical-app中的任何容器或任何名为skydns的进程的套接字IPv4或IPv6上的流量。加入proc.name = skydns因为这是内部Kubernetes DNS解析器,并且作为Kubernetes基础结构的一部分运行在我们的命名空间之外。

未分类

Sysdig也有一个交互式的ncurses接口。

为了跟随此服务发现故障排除示例,你可以下载捕获文件capture.scap并使用sysdig自行查看它。

我们立即看到curl如何尝试解析域名,但在DNS查询有效载荷上我们有些奇怪(10049):backend.critical-app.svc.cluster.local.critical-app.svc.cluster.local。看上去由于某些原因,curl不识别已经给定的FQDN,并且决定追加一个搜索域。

[...]
10030 16:41:39.536689965 0 client (b3a718d8b339) curl (22370:13) < socket fd=3(<4>)
10031 16:41:39.536694724 0 client (b3a718d8b339) curl (22370:13) > connect fd=3(<4>)
10032 16:41:39.536703160 0 client (b3a718d8b339) curl (22370:13) < connect res=0 tuple=172.17.0.7:46162->10.0.2.15:53
10048 16:41:39.536831645 1  (36ae6d09d26e) skydns (17280:11) > recvmsg fd=6(<3t>:::53)
10049 16:41:39.536834352 1  (36ae6d09d26e) skydns (17280:11) < recvmsg res=87 size=87 data=
backendcritical-appsvcclusterlocalcritical-appsvcclusterlocal tuple=::ffff:172.17.0.7:46162->:::53
10050 16:41:39.536837173 1  (36ae6d09d26e) skydns (17280:11) > recvmsg fd=6(<3t>:::53)
[...]

SkyDNS发送请求(10097)到etcd的API(/local/cluster/svc/critical-app/local/cluster/svc/critical-app/backend),显然etcd不能识别这个service,然后返回(10167)“Key not found”。这通过DNS查询响应传回给curl。

[...]
10096 16:41:39.538247116 1  (36ae6d09d26e) skydns (4639:8) > write fd=3(<4t>10.0.2.15:34108->10.0.2.15:4001) size=221
10097 16:41:39.538275108 1  (36ae6d09d26e) skydns (4639:8) < write res=221 data=
GET /v2/keys/skydns/local/cluster/svc/critical-app/local/cluster/svc/critical-app/backend?quorum=false&recursive=true&sorted=false HTTP/1.1
Host: 10.0.2.15:4001
User-Agent: Go 1.1 package http
Accept-Encoding: gzip


10166 16:41:39.538636659 1  (36ae6d09d26e) skydns (4617:1) > read fd=3(<4t>10.0.2.15:34108->10.0.2.15:4001) size=4096
10167 16:41:39.538638040 1  (36ae6d09d26e) skydns (4617:1) < read res=285 data=
HTTP/1.1 404 Not Found
Content-Type: application/json
X-Etcd-Cluster-Id: 7e27652122e8b2ae
X-Etcd-Index: 1259
Date: Thu, 08 Dec 2016 15:41:39 GMT
Content-Length: 112

{"errorCode":100,"message":"Key not found","cause":"/skydns/local/cluster/svc/critical-app/local","index":1259}
[...]

curl没有放弃并再次尝试(10242),不过这次用的是backend.critical-app.svc.cluster.local.svc.cluster.local。看起来这次curl尝试将critical-app这个追加搜索域去除,使用一个不同的搜索域。显然,当请求到达etcd(10247)时,再次失败(10345)。

[...]
10218 16:41:39.538914765 0 client (b3a718d8b339) curl (22370:13) < connect res=0 tuple=172.17.0.7:35547->10.0.2.15:53
10242 16:41:39.539005618 1  (36ae6d09d26e) skydns (17280:11) < recvmsg res=74 size=74 data=
backendcritical-appsvcclusterlocalsvcclusterlocal tuple=::ffff:172.17.0.7:35547->:::53
10247 16:41:39.539018226 1  (36ae6d09d26e) skydns (17280:11) > recvmsg fd=6(<3t>:::53)
10248 16:41:39.539019925 1  (36ae6d09d26e) skydns (17280:11) < recvmsg res=74 size=74 data=
0]backendcritical-appsvcclusterlocalsvcclusterlocal tuple=::ffff:172.17.0.7:35547->:::53
10249 16:41:39.539022522 1  (36ae6d09d26e) skydns (17280:11) > recvmsg fd=6(<3t>:::53)
10273 16:41:39.539210393 1  (36ae6d09d26e) skydns (4639:8) > write fd=3(<4t>10.0.2.15:34108->10.0.2.15:4001) size=208
10274 16:41:39.539239613 1  (36ae6d09d26e) skydns (4639:8) < write res=208 data=
GET /v2/keys/skydns/local/cluster/svc/local/cluster/svc/critical-app/backend?quorum=false&recursive=true&sorted=false HTTP/1.1
Host: 10.0.2.15:4001
User-Agent: Go 1.1 package http
Accept-Encoding: gzip


10343 16:41:39.539465153 1  (36ae6d09d26e) skydns (4617:1) > read fd=3(<4t>10.0.2.15:34108->10.0.2.15:4001) size=4096
10345 16:41:39.539467440 1  (36ae6d09d26e) skydns (4617:1) < read res=271 data=
HTTP/1.1 404 Not Found
[...]

curl会再次尝试,我们可以看这次的DNS查询请求(10418),加上了cluster.local变成backend.critical-app.svc.cluster.local.cluster.local。这次etcd请求(10479)同样失败(10524)。

[...]
10396 16:41:39.539686075 0 client (b3a718d8b339) curl (22370:13) < connect res=0 tuple=172.17.0.7:40788->10.0.2.15:53
10418 16:41:39.539755453 0  (36ae6d09d26e) skydns (17280:11) < recvmsg res=70 size=70 data=
backendcritical-appsvcclusterlocalclusterlocal tuple=::ffff:172.17.0.7:40788->:::53
10433 16:41:39.539800679 0  (36ae6d09d26e) skydns (17280:11) > recvmsg fd=6(<3t>:::53)
10434 16:41:39.539802549 0  (36ae6d09d26e) skydns (17280:11) < recvmsg res=70 size=70 data=
backendcritical-appsvcclusterlocalclusterlocal tuple=::ffff:172.17.0.7:40788->:::53
10437 16:41:39.539805177 0  (36ae6d09d26e) skydns (17280:11) > recvmsg fd=6(<3t>:::53)
10478 16:41:39.540166087 1  (36ae6d09d26e) skydns (4639:8) > write fd=3(<4t>10.0.2.15:34108->10.0.2.15:4001) size=204
10479 16:41:39.540183401 1  (36ae6d09d26e) skydns (4639:8) < write res=204 data=
GET /v2/keys/skydns/local/cluster/local/cluster/svc/critical-app/backend?quorum=false&recursive=true&sorted=false HTTP/1.1
Host: 10.0.2.15:4001
User-Agent: Go 1.1 package http
Accept-Encoding: gzip


10523 16:41:39.540421040 1  (36ae6d09d26e) skydns (4617:1) > read fd=3(<4t>10.0.2.15:34108->10.0.2.15:4001) size=4096
10524 16:41:39.540422241 1  (36ae6d09d26e) skydns (4617:1) < read res=267 data=
HTTP/1.1 404 Not Found
[...]

对于未经训练的人来说,可能看起来我们发现了这个问题:一堆无效的请求。但实际上这不是事实,如果我们查看时间戳,第一个etcd请求(10097)和最后一个(10479)之间的差异,第二列中的时间戳相距小于10ms。而我们正在寻找一个秒数问题,而不是毫秒——那么等待的时间在哪里?

当我们继续浏览捕获文件时,我们可以看到curl不停止尝试使用DNS查询到SkyDNS,现在使用backend.critical-app.svc.cluster.local.localdomain(10703)。这个.localdomain不被SkyDNS识别为Kubernetes的内部域,因此它决定将这个查询转发给它的上游DNS解析器(10691),而不是去etcd进行服务发现。

[...]
10690 16:41:39.541376928 1  (36ae6d09d26e) skydns (4639:8) > connect fd=8(<4>)
10691 16:41:39.541381577 1  (36ae6d09d26e) skydns (4639:8) < connect res=0 tuple=10.0.2.15:44249->8.8.8.8:53
10702 16:41:39.541415384 1  (36ae6d09d26e) skydns (4639:8) > write fd=8(<4u>10.0.2.15:44249->8.8.8.8:53) size=68
10703 16:41:39.541531434 1  (36ae6d09d26e) skydns (4639:8) < write res=68 data=
Nbackendcritical-appsvcclusterlocallocaldomain
10717 16:41:39.541629507 1  (36ae6d09d26e) skydns (4639:8) > read fd=8(<4u>10.0.2.15:44249->8.8.8.8:53) size=512
10718 16:41:39.541632726 1  (36ae6d09d26e) skydns (4639:8) < read res=-11(EAGAIN) data=
58215 16:41:43.541261462 1  (36ae6d09d26e) skydns (4640:9) > close fd=7(<4u>10.0.2.15:54272->8.8.8.8:53)
58216 16:41:43.541263355 1  (36ae6d09d26e) skydns (4640:9) < close res=0
[...]

扫描时间戳列时,我们发现SkyDNS发出请求后第一个较大的间隙,然后等待大约4秒(10718-58215)。鉴于.localdomain不是有效的TLD(顶级域名),上游服务器将只是忽略此请求。超时后,SkyDNS再次尝试使用相同的查询(75923),再等待几秒钟(75927-104208)。总的来说,我们一直在等待大约8秒钟,以查找不存在并且被忽略的DNS条目。

[...]
58292 16:41:43.542822050 1  (36ae6d09d26e) skydns (4640:9) < write res=68 data=
Nbackendcritical-appsvcclusterlocallocaldomain
58293 16:41:43.542829001 1  (36ae6d09d26e) skydns (4640:9) > read fd=8(<4u>10.0.2.15:56371->8.8.8.8:53) size=512
58294 16:41:43.542831896 1  (36ae6d09d26e) skydns (4640:9) < read res=-11(EAGAIN) data=
75904 16:41:44.543459524 0  (36ae6d09d26e) skydns (17280:11) < recvmsg res=68 size=68 data=
[...]
75923 16:41:44.543560717 0  (36ae6d09d26e) skydns (17280:11) < recvmsg res=68 size=68 data=
Nbackendcritical-appsvcclusterlocallocaldomain tuple=::ffff:172.17.0.7:47441->:::53
75927 16:41:44.543569823 0  (36ae6d09d26e) skydns (17280:11) > recvmsg fd=6(<3t>:::53)
104208 16:41:47.551459027 1  (36ae6d09d26e) skydns (4640:9) > close fd=7(<4u>10.0.2.15:42126->8.8.8.8:53)
104209 16:41:47.551460674 1  (36ae6d09d26e) skydns (4640:9) < close res=0
[...]

但最后,它一切正常!为什么?curl停止尝试修补事物并应用搜索域。当我们在命令行中输入时,它会逐字尝试域名。SkyDNS通过etcd服务发现API请求解析DNS请求(104406)。打开一个与服务IP地址(107992)的连接,然后使用iptables将其转发给Pod,并且HTTP响应返回到curl容器(108024)。

[...]
104406 16:41:47.552626262 0  (36ae6d09d26e) skydns (4639:8) < write res=190 data=
GET /v2/keys/skydns/local/cluster/svc/critical-app/backend?quorum=false&recursive=true&sorted=false HTTP/1.1
[...]
104457 16:41:47.552919333 1  (36ae6d09d26e) skydns (4617:1) < read res=543 data=
HTTP/1.1 200 OK
[...]
{"action":"get","node":{"key":"/skydns/local/cluster/svc/critical-app/backend","dir":true,"nodes":[{"key":"/skydns/local/cluster/svc/critical-app/back
end/6ead029a","value":"{"host":"10.3.0.214","priority":10,"weight":10,"ttl":30,"targetstrip":0}","modifiedIndex":270,"createdIndex":270}],
"modifiedIndex":270,"createdIndex":270}}
[...]
107992 16:41:48.087346702 1 client (b3a718d8b339) curl (22369:12) < connect res=-115(EINPROGRESS) tuple=172.17.0.7:36404->10.3.0.214:80
108002 16:41:48.087377769 1 client (b3a718d8b339) curl (22369:12) > sendto fd=3(<4t>172.17.0.7:36404->10.3.0.214:80) size=102 tuple=NULL
108005 16:41:48.087401339 0 backend-1440326531-csj02 (730a6f492270) nginx (7203:6) < accept fd=3(<4t>172.17.0.7:36404->172.17.0.5:80) tuple=172.17.0.7:36404->172.17.0.5:80 queuepct=0 queuelen=0 queuemax=128
108006 16:41:48.087406626 1 client (b3a718d8b339) curl (22369:12) < sendto res=102 data=
GET / HTTP/1.1
[...]
108024 16:41:48.087541774 0 backend-1440326531-csj02 (730a6f492270) nginx (7203:6) < writev res=238 data=
HTTP/1.1 200 OK
Server: nginx/1.10.2
[...]

通过系统层面的情况,我们可以得出结论:造成这个问题的根本原因有两个方面。首先,当我给curl一个FQDN时,它不相信我并试图应用搜索域算法。其次,.localdomain不应该存在,因为它在我们的Kubernetes集群中是不可路由的。

如果你认为这是通过使用tcpdump也能完成,只是你还没尝试。我能100%肯定它不会被安装在你的容器内,你可以在主机外部运行它,但祝你找到与对应Kubernetes调度容器的网络命名空间匹配的网络接口。请继续阅读:我们还没有完成故障排除。

第二部分:Kubernetes故障排除之DNS解析

让我们看看resolv.conf文件中的内容。容器可能已经不存在了,或者curl调用后文件可能已经改变。但是我们有一个包含发生了所有事情的捕获文件。

通常情况下,容器的运行时间与进程内运行的时间一样长,当进程结束时容器就消失了。这是对容器进行故障排除最具挑战性的部分之一。我们如何探索已经消失的东西?我们如何重现发生的事情?在这些情况下,Sysdig捕获文件非常有用。

我们来分析捕获文件,但不是过滤网络流量,我们将在这次对resolv文件进行过滤。我们希望看到resolv.conf与curl读取的完全一样,以确认我们的想法,它包含localdomain。

$ sysdig -pk -NA -r capture.scap -c echo_fds "fd.type=file and fd.name=/etc/resolv.conf"
------ Read 119B from  [k8s_client.eee910bc_client_critical-app_da587b4d-bd5a-11e6-8bdb-028ce2cfb533_bacd01b6] [b3a718d8b339]  /etc/resolv.conf (curl)

search critical-app.svc.cluster.local svc.cluster.local cluster.local localdomain
nameserver 10.0.2.15
options ndots:5
[...]

这是使用sysdig的一种新的方式:

-c echo_fds 使用Sysdig chisel——附加脚本——用以聚合信息并格式化输出。此外,过滤器仅包含文件描述符上的IO活动,该文件描述符是一个文件,名称为/etc/resolv.conf,正是我们所要寻找的。

通过系统调用,我们看到有一个选项叫做ndots。 此选项是curl不信任我们的FQDN并试图首先追加所有搜索域的原因。如果你阅读了manpage,就会知道ndots会强制libc,任何小于5个点的域名解析都不会被视为fqdn,但会尝试首先追加所有搜索域。ndots有一个很好的理由,所以我们可以执行 curl backend。但是谁在那里添加了localdomain?

第三部分:Kubernetes故障排除之使用Docker运行容器

我们不想在没有找到这个本地域的罪魁祸首的情况下完成我们的故障排除。 这样,我们可以责怪软件而不是人,是Docker加了搜索域?或者Kubernetes在创建容器时指导Docker这么做?

既然我们知道Kubernetes和Docker之间的所有控制通信都是通过Unix套接字完成的,我们可以使用它来过滤掉所有的东西:

$ sudo sysdig -pk -s8192 -c echo_fds -NA "fd.type in (unix) and evt.buffer contains localdomain"

这一次,我们将使用一个非常棒的过滤器的来捕捉现场 evt.buffer containers。 这个过滤器需要所有的事件缓冲区,如果它包含我们正在寻找的字符串,将被我们的chisel捕获并格式化输出。

现在我需要创建一个新的客户端来窥探容器编排时发生的情况:

$ kubectl run -it --image=tutum/curl client-foobar --namespace critical-app --restart=Never

可以看到,Kubernetes中的hyperkube使用Docker API在/var/run/docker.sock上写了一个HTTP POST请求到/containers/create。如果我们通读它,我们会发现这个请求包含一个选项“DnsSearch”:[“critical-app.svc.cluster.local”,“svc.cluster.local”,“cluster.local”,“localdomain”]。Kubernetes,我们抓到你了!很可能它出于某种原因,就像我的本地开发机器设置了该搜索域一样。无论如何,这是一个不同的故事。

[...]
------ Write 2.61KB to  [k8s-kubelet] [de7157ba23c4]   (hyperkube)

POST /containers/create?name=k8s_POD.d8dbe16c_client-foobar_critical-app_085ac98f-bd64-11e6-8bdb-028ce2cfb533_9430448e HTTP/1.1
Host: docker
[...]
"DnsSearch":["critical-app.svc.cluster.local","svc.cluster.local","cluster.local","localdomain"],
[...]

总结

准确地再现容器内发生的事情可能会非常具有挑战性,因为它们在进程死亡或刚刚结束时终止。Sysdig捕获通过系统调用包含所有信息,包括网络流量、文件系统I/O和进程行为,提供故障排除所需的所有数据。

在容器环境中进行故障排除时,能够过滤和添加容器上下文信息(如Docker容器名称或Kubernetes元数据)使我们的排查过程更加轻松。

Sysdis在所有主流Linux发行版、OSX以及Windows上都能使用,下载它获得最新版本。Sysdig是一个开源工具,但该项目背后的公司也提供了一个商业产品来监视和排除多个主机上的容器和微服务。

Kubernetes监控系列(二):Kubernetes集群的监控报警策略最佳实践

【编者的话】本文是Kubernetes监控系列的第二篇,主要讲述了配置Kubernetes报警的一些最佳实践。

本文将介绍关于如何在Kubernetes集群中配置基础设施层的警报。本文是关于在生产中使用Kubernetes系列的一部分。第一部分介绍了Kubernetes和监控工具的基础知识;这部分涵盖了Kubernetes报警的最佳实践,第三部分将介绍Kubernetes服务发现与故障排除,最后一部分是监控Kubernetes的实际使用案例。

监控是每个优质基础设施的基础,是达到可靠性层次的基础。监控有助于减少对突发事件的响应时间,实现对系统问题的检测、故障排除和调试。在基础设施高度动态的云时代,监控也是容量规划的基础。

有效的警报是监控策略的基石。当你转向容器和Kubernetes编排环境,你的警报策略也需要演进。正是因为以下几个核心原因,其中许多我们在”如何监视Kubernetes”中进行了讲述:

  • 可见性:容器是一个黑盒。传统工具只能针对公共监控端点进行检查。如果想深入监控相关服务,则需要采取不一样的方法。
  • 新的基础架构层:现在服务和主机之间有一个新的层:容器和容器编排服务。这些是你需要监控的新内部服务,你的监控系统需要了解这些服务。
  • 动态重调度:容器没有像之前那样的服务节点,所以传统的监控不能有效地工作。没有获取服务度量标准的静态端点,没有运行服务实例的静态数量(设想一个金丝雀发布或自动伸缩设置)。在某节点中一个进程被kill是正常的,因为它有很大的机会被重新调度到基础设施的其他节点。
  • 元数据和标签:随着服务跨多个容器,为所有这些服务添加系统级别的监控以及服务特定的度量标准,再加上Kubernetes带来的所有新服务,如何让所有这些信息对我们有所帮助?有时你希望看到分布在不同节点容器中的服务的网络请求度量,有时你希望看到特定节点中所有容器的相同度量,而不关心它们属于哪个服务。这就需要一个多维度量系统,需要从不同的角度来看待这些指标。如果通过Kubernetes中存在的不同标签自动标记度量标准,并且监控系统能够了解Kubernetes元数据,那么只需要在每种情况下按照需要聚合和分割度量标准就可以实现多维度度量。

考虑到这些问题,让我们创建一组对Kubernetes环境至关重要的报警策略。我们的Kubernetes报警策略教程将涵盖:

  • 应用程序层度量标准的报警
  • Kubernetes上运行的服务的报警
  • Kubernetes基础设施的报警
  • 在主机/节点层上的报警

最后我们还将通过检测系统调用问题来了解如何通过报警加速故障排除。

应用程序层度量标准的报警

工作指标(working metrics)可以确认应用程序是否按预期执行,这些度量标准通常来自用户或消费者对服务的期望操作,或者是由应用程序通过statsd或JMX在内部生成。如果监控系统本身提供网络数据,就可以使用它来创建基于响应时间的报警策略。

以下示例是一个公共REST API端点监控警报,监控prod命令空间中的名为javaapp的deployment,在10分钟内如果延迟超过1秒则报警。

未分类

所有这些报警高度依赖于应用程序、工作负载模式等等,但真正的问题是如何在所有服务中一致性地获取数据。在理想环境中,除了核心监控工具之外,无需再购买综合监控服务即可获得这一套关键指标。

这个类别中经常出现的一些指标和报警是:

  • 服务相应时间
  • 服务可用性
  • SLA合规性
  • 每秒请求的成功/失败数

Kubernetes上运行的服务的报警

对于服务级别,和使用Kubernetes之前对于服务集群需要做的事情应该没什么不同。试想下,当在MySQL/MariaDB或者MongoDB等数据库服务中查看副本状态与延迟时,需要考虑些什么?

没错,如果想知道服务的全局运行和执行情况,就需要利用监视工具功能根据容器元数据将度量标准进行聚合和分段。

如第一篇文章所述,Kubernetes将容器标记为一个deployment或者通过一个service进行暴露,在定义报警时就需要考虑这些因素,例如针对生产环境的报警(可能通过命名空间进行定义)。

以下是Cassandra集群的示例:

未分类

如果我们在Kubernetes、AWS EC2或OpenStack中运行Cassandra,则衡量指标cassandra.compactions.pending存在每个实例上,但是现在我们要查看在prod命名空间内的cassandra复制控制器中聚合的指标。这两个标签都来自Kubernetes,但我们也可以更改范围,包括来自AWS或其他云提供商的标签,例如可用区域。

这个类别中经常出现的一些指标和警报是:

  • HTTP请求数
  • 数据库连接数、副本数
  • 线程数、文件描述符数、连接数
  • 中间件特定指标:Python uwsgi worker数量,JVM堆大小等

另外,如果正在使用外部托管服务,则很可能需要从这些提供程序导入度量标准,因为它们可能还有需要做出反应的事件。

Kubernetes基础设施的报警

在容器编排层面的监控和报警有两个层面。一方面,我们需要监控Kubernetes所处理的服务是否符合所定义的要求。另一方面,我们需要确保Kubernetes的所有组件都正常运行。
由Kubernetes处理的服务

1.1 是否有足够的Pod/Container给每个应用程序运行?

Kubernetes可以通过Deployments、Replica Sets和Replication Controllers来处理具有多个Pod的应用程序。它们之间区别比较小,可以使用它们来维护运行相同应用程序的多个实例。运行实例的数量可以动态地进行伸缩,甚至可以通过自动缩放来实现自动化。

运行容器数量可能发生变化的原因有多种:因为节点失败或资源不足将容器重新调度到不同主机或者进行新版本的滚动部署等。如果在延长的时间段内运行的副本数或实例的数量低于我们所需的副本数,则表示某些组件工作不正常(缺少足够的节点或资源、Kubernetes或Docker Engine故障、Docker镜像损坏等等)。

在Kubernetes部署服务中,跨多个服务进行如下报警策略对比是非常有必要的:

timeAvg(kubernetes.replicaSet.replicas.running) < timeAvg(kubernetes.replicaSet.replicas.desired)

正如之前所说,在重新调度与迁移过程运行中的实例副本数少于预期是可接受的,所以对每个容器需要关注配置项 .spec.minReadySeconds (表示容器从启动到可用状态的时间)。你可能也需要检查 .spec.strategy.rollingUpdate.maxUnavailable 配置项,它定义了在滚动部署期间有多少容器可以处于不可用状态。

下面是上述报警策略的一个示例,在 wordpress 命名空间中集群 kubernetes-dev 的一个deployment wordpress-wordpress

未分类

1.2 是否有给定应用程序的任何Pod/Container?

与之前的警报类似,但具有更高的优先级(例如,这个应用程序是半夜获取页面的备选对象),将提醒是否没有为给定应用程序运行容器。

以下示例,在相同的deployment中增加警报,但不同的是1分钟内运行Pod <1时触发:

未分类

1.3 重启循环中是否有任何Pod/Container?

在部署新版本时,如果没有足够的可用资源,或者只是某些需求或依赖关系不存在,容器或Pod最终可能会在循环中持续重新启动。这种情况称为“CrashLoopBackOff”。发生这种情况时,Pod永远不会进入就绪状态,从而被视为不可用,并且不会处于运行状态,因此,这种场景已被报警覆盖。尽管如此,笔者仍希望设置一个警报,以便在整个基础架构中捕捉到这种行为,立即了解具体问题。这不是那种中断睡眠的报警,但会有不少有用的信息。

这是在整个基础架构中应用的一个示例,在过去的2分钟内检测到4次以上的重新启动:

未分类

监控Kubernetes系统服务

除了确保Kubernetes能正常完成其工作之外,我们还希望监测Kubernetes的内部健康状况。这将取决于Kubernetes集群安装的不同组件,因为这些可能会根据不同部署选择而改变,但有一些基本组件是相同的。

2.1 etcd是否正常运行?

etcd是Kubernetes的分布式服务发现、通信、命令通道。监控etcd可以像监控任何分布式键值数据库一样深入,但会使事情变得简单。

未分类

我们可以进一步去监控设置命令失败或者节点数,但是我们将会把它留给未来的etcd监控文章来描述。

2.2 集群中有足够的节点吗?

节点故障在Kubernetes中不是问题,调度程序将在其他可用节点中生成容器。但是,如果我们耗尽节点呢?或者已部署的应用程序的资源需求超过了现有节点?或者我们达到配额限制?

在这种情况下发出警报并不容易,因为这取决于你想要在待机状态下有多少个节点,或者你想要在现有节点上推送多少超额配置。可以使用监控度量值kube_node_status_ready和kube_node_spec_unschedulable进行节点状态警报。

如果要进行容量级别报警,则必须将每个已调度Pod请求的CPU和memory进行累加,然后检查是否会覆盖每个节点,使用监控度量值kube_node_status_capacity_cpu_cores和kube_node_status_capacity_memory_bytes。

在主机/节点层上的报警

主机层的警报与监视虚拟机或物理机区别不大,主要是关于主机是启动还是关闭或不可访问状态,以及资源可用性(CPU、内存、磁盘等)。

主要区别是现在警报的严重程度。在此之前,系统服务宕机可能意味着你的应用程序停止运行并且要紧急处理事故(禁止有效的高可用性)。而对于Kubernetes来说当服务发生异常,服务可以在主机之间移动,主机警报不应该不受重视。

让我们看看我们应该考虑的几个方面:

1. 主机宕机

如果主机停机或无法访问,我们希望收到通知。我们将在整个基础架构中应用此单一警报。我们打算给它一个5分钟的等待时间,因为我们不想看到网络连接问题上的嘈杂警报。你可能希望将其降低到1或2分钟,具体取决于你希望接收通知的速度。

未分类

2. 磁盘利用率

这是稍微复杂一些的警报。我们在整个基础架构的所有文件系统中应用此警报。我们将范围设置为 everywhere,并针对每个 fs.mountDir 设置单独的评估/警报。

以下是超过80%使用率的通用警报,但你可能需要不同的策略,如具有更高阈值(95%)或不同阈值的更高优先级警报(具体取决于文件系统)。

未分类

如果要为不同的服务或主机创建不同的阈值,只需更改要应用特定阈值的范围。

3. 一些其他资源

此类别中的常见资源是有关负载、CPU使用率、内存和交换空间使用情况的警报。如果在一定的时间内这些数据中的任何一个显著提升,可能就需要警报提醒您。我们需要在阈值、等待时间以及如何判定噪声警报之间进行折中。

如果您想为这些资源设置指标,请参考以下指标:

  • 负载:load.average.1m, load.average.5m 和 load.average.15m
  • CPU:cpu.used.percent
  • memory:memory.used.percent 或 memory.bytes.used
  • swap:memory.swap.used.percent 或 memory.swap.bytes.used

一些人同样使用这个类别监控他们部分基础架构所在云服务提供商的资源。

Sysdig额外监控:监控系统调用

从警报触发并收到通知的那一刻起,真正的工作就开始为DevOps值班成员开展工作。有时运行手册就像检查工作负载中的轻微异常一样简单。这可能是云提供商的一个事件,但希望Kubernetes正在处理这个问题,并且只需要花费一些时间来应对负载。

但是如果一些更棘手的问题出现在我们面前,我们可以看到我们拥有的所有武器:提供者状态页面、日志(希望来自中心位置)、任何形式的APM或分布式追踪(如果开发人员安装了代码或者外部综合监测)。然后,我们祈祷这一事件在这些地方留下了一些线索,以便我们可以追溯到问题出现的多种来源原因。

我们怎么能够在警报被解除时自动dump所有系统调用?系统调用是所发生事情的真实来源,并将包含我们可以获得的所有信息。通过系统调用有可能发现触发警报的根本问题所在。Sysdig Monitor允许在警报触发时自动开始捕获所有系统调用。

例如,可以配置CrashLoopBackOff场景:

未分类

只有当你安装代码后,Sysdig Monitor代理才能从系统调用拦截中计算出来相应的指标。考虑HTTP响应时间或SQL响应时间。Sysdig Monitor代理程序在套接字上捕获read()和write()系统调用,解码应用程序协议并计算转发到我们时间序列数据库中的指标。这样做的好处是可以在不触及开发人员代码的情况下获得仪表盘数据和警报:

未分类

结论

我们已经看到如何使用容器编排平台来增加系统中移动部分的数量。拥有容器本地监控是建立可靠基础架构的关键要素。监控不能仅仅关注基础架构,而是需要从底层的主机到应用程序指标所在的顶端来了解整个技术栈。

能够利用Kubernetes和云服务提供商的元数据信息来汇总和细分监控指标和警报将成为多层次有效监控的必要条件。我们已经看到如何使用标签来更新我们已有的警报或创建Kubernetes上所需的新警报。

接下来,让我们看看在Kubernetes编排环境中的典型服务发现故障排除的挑战。

视频:https://v.qq.com/x/page/s06032nah0m.html

Kubernetes监控系列(一):Kubernetes监控开源工具基本介绍以及如何使用Sysdig进行监控

【编者的话】Kubernetes监控系列一共有四篇文章,此篇是该系列的首篇文章,主要介绍了一些Kubernetes监控的开源工具,并着重介绍了Sysdig这个监控工具。

在GitHub上有超过21000颗星,超过一千个提交者,以及一个包括Google、RedHat、Intel在内的生态系统,Kubernetes已经让容器生态系统风靡一时。Kubernetes这么火是因为它充当了分布式容器部署的大脑,它旨在使用分布在宿主机集群上的容器来管理面向服务的应用程序。Kubernetes为应用程序部署、服务发现、调度、更新、运维以及扩容提供了相关机制,但对于Kubernetes监控呢?

虽然Kubernetes能够显著简化在容器中以及在云上部署应用程序的过程,但同时它也增加了日常管理应用程序性能、获取服务可见性以及监控->报警->故障排除流程的复杂性。

基础设施层次的新型复杂性出现在期望简化应用程序部署的过程中:通过IaaS层动态配置;使用配置管理工具自动配置;以及使用像Kubernetes一样的编排工具,这些编排工具介于裸机或者虚机基础设施和支持应用程序的服务之间。

未分类

除了增加基础设施复杂性之外,应用程序正在被设计成微服务,在微服务结构中,更多组件之间需要互相通信。每个服务都可以分布在多个实例上,Docker容器根据需求跨越基础设施。在我们知道每个服务组件有多少实例以及它们的部署位置之前,情况就不再是这样了。这会怎么影响Kubernetes监控的方法和工具呢?正如 Site Reliability Engineering – How Google Runs Production Systems中所述,“我们需要监控系统,让我对高层次服务目标保持警惕,但也要根据需求保持对单个组件粒度的监控”。考虑到这一点,这篇博客是一个系列中的第一篇,帮助您更好地理解在生产中使用Kubernetes的行为。 这四部分组成的系列包括:

  • 第一部分(本篇):Kubernetes监控开源工具的基本介绍以及使用Sysdig进行监控。

  • 第二部分:Kubernetes报警的最佳实践

  • 第三部分:通过系统捕获对Kubernetes服务发现进行故障排除
  • 第四部分:WayBlazer的Kubernetes监控(一个示例)

了解Kubernetes及其复杂性

从物理/基础设施的角度来看,Kubernetes集群由一组master节点监控的nodes组成。master节点的任务包括跨node节点的容器编排、状态追踪以及通过REST API和UI界面暴露集群控制。

另一方面,从逻辑/应用的角度来看,Kubernetes集群按照图中所示的层级方式排列:

未分类

所有容器运行在Pods中,一个Pod是一组容器集合。这些容器总是部署在一起并且一起进行调度,它们运行在共享的环境中并且拥有共享的存储。Pod中的容器被保证部署在相同的机器上,可以共享资源。

  • Pods位于services之后,service主要负责负载均衡,并且将一组Pod作为一个可发现的IP地址/端口进行暴露。
  • Services通过replica sets(之前成为副本控制器)进行水平伸缩,它根据需求为每个服务创建/销毁Pod。
  • ReplicaSets由deployments进行控制,它允许对运行中的replicasets以及Pods进行状态申明。
  • Namespaces代表虚拟集群,可以包含一个或者多个services。
  • Metadata允许使用labels和tags基于容器的部署特性进行标记。

所以需要搞清楚的是,多个services甚至多个namespaces可以分散在同一个物理基础设施中。每个service都由多个Pod构建,而每个Pod都有多个container构成,这就为监控增加了一定程度的复杂性,即使是适度的Kubernetes部署也是如此。

让我们来看看Kubernetes本身提供的解决方案。

如何收集Kubernetes监控数据:开源工具

和大多数平台一样,Kubernetes有一套基本的工具,可以让你监控你的服务器,在这种情况下,Kubernetes可以直接部署在物理基础设施之上。“内置”一词可能有点言过其实,更公正地说,考虑到Kubernetes的可扩展性,你可以添加额外的组件来获取Kubernetes的可见性,让我们来看看其中的几个选择:

  • Probes
  • cAdvisor
  • Heapster
  • Kubernetes Dashboard
  • Kebu-state-metrics

之后我们将对比一下这些选择和使用Sysdig进行监控。

Liveness和Readiness Probes

Kubernetes Probes具有定期监测集装箱或服务的健康状况的重要功能,并在发生不健康的事件时采取行动。Kubernetes监控探针允许你通过设定一个特定的命令来定义“Liveness”状态,这个命令应该在Pod中成功执行。你还可以设定Liveness探针执行的频率。以下是一个简单的示例,基于cat命令。

#Example Liveness probe for the Sysdig Blog on "Monitoring Kubernetes"

apiVersion: v1
kind: Pod

metadata:
labels:
test: liveness
name: liveness-exec
spec:
containers:

-name: liveness
args:
- /bin/sh
- -c
- touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600

image: gcr.io/google_containers/busybox

livenessProbe:
  exec:
    command:
    - cat
    - /tmp/healthy
  initialDelaySeconds: 5
  periodSeconds: 5

  #source https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/

Readiness Probe某种程度上说是Liveness Probe的修正版,同样它是执行一条命令来检测Pod在启动/重启后是否准备好进行工作。

cAdvisor和Heapster

cAdvisor是一个开源的容器资源使用收集器。它是专门为容器构建的,原生支持Docker容器。与在Pod级别运行的Kubernetes中的大多数元素不同,cAdvisor在每个node节点上运行。它会自动发现给定node节点中的所有容器,并收集CPU,内存,文件系统和网络使用统计信息。cAdvisor还通过分析机器上的“root”容器来提供整体机器使用情况。不过,cAdvisor两个方面有限制性:

  1. 它只能收集一些基本的资源利用信息——cAdvisor不能够告诉你应用程序的真实性能,它只能告诉你一个容器使用了X% CPU信息。
  2. cAdvisor自身没有提供任何长期存储、趋势或者分析功能。

为了进一步处理这些数据,我们需要添加Heapster。Heapster会聚集Kubernetes集群中所有节点上的数据。Heapster作为集群中的一个Pod运行,就像其他应用程序一样。Heapster Pod通过节点上Kubelets(机器上的Kubernetes agent)查询使用信息,而Kubelets又查询来自cAdvisor的数据。最终,Heapster将来自相关标签的Pod信息进行分组。

未分类

在Kubernetes中使用Heapster和cAdvisor进行监控,来源:blog.kubernetes.io

不过,Heapster也不能够进行存储数据、趋势分析以及报警。它只是让你更容易在整个集群中收集cAdvisor数据。所以,你还需要将数据推送到可配置的后端进行存储和可视化,目前支持的后端包括InfluxDB,Google Cloud Monitoring等。此外,你还必须添加一个和Grafana一样的可视化图层来查看数据。

Kubernetes Dashboard

最近比较流行使用Kubernets插件提供一致性方式来查看一些基础数据以及管理集群环境。Kubernetes Dashboard提供了一种依据Kubernetes元数据来查看您的环境的简单方式。它有两个优势:基本的CPU/内存数据是可用的,以及可以在Dashboard上采取行动。

未分类

简单通过kubectl安装Dashboard,Kubernetes命令:

$ kubectl create -f https://rawgit.com/kubernetes/dashboard/master/src/deploy/kubernetes-dashboard.yaml

然后在安装了Dashboard的机器上通过localhost进行访问:http://localhost:8001/ui。

kube-state-metrics:作为监控设置的补充

除了配置cAdvisor/Heapster/Influx/Grafana之外,还可以考虑部署kube-state-metrics。这是一个附加服务,与Heapster一起运行,它会轮询Kubernetes API并将有关你的Kubernetes结构化特征信息转换为metrics信息。以下是kube-state-metrics会回答的一些问题:

  • 我调度了多少个replicas?现在可用的有几个?
  • 多少个Pod是running/stopped/terminated状态?
  • Pod重启了多少次?

……等等。一般来说,该模型将采集Kubernetes事件并将其转换为metrics信息。需要Kubernetes 1.2+版本,不过,需要提醒的是metrics名称和标签是不稳定的,可能会改变。

通过以上介绍,至少可以让你了解如何为你的Kubernetes环境构建合理的监控配置。虽然我们仍然没有详细的应用程序监控(例如:“我的数据库服务的响应时间是多少?”),但我们至少可以看到我们的宿主机,Kubernetes节点以及我们的Kubernetes抽象状态的一些监控。

让我们来看看Sysdig进行Kubernetes监控的方式。

使用Sysdig进行Kubernetes监控

在与数百名Kubernetes用户交谈之后,似乎典型的集群管理员往往有兴趣从物理角度来看事物,而负责构建服务的应用程序开发人员往往更倾向于从逻辑角度来看事物。无论你从什么角度进行观察,所有团队都希望减少他们为了测试系统或管理数据收集而需要完成的工作量。

考虑到这两个用例,Sysdig Monitor对Kubernetes的支持现在可以做到:

  1. 通过连接到Kubernetes的集群API服务器并查询API(常规API和观察API)我们现在可以推断出您的微服务应用程序物理和逻辑结构。
  2. 另外,我们透传获取到的重要元数据信息,例如labels。
  3. 这些信息与我们的ContainerVision技术相结合,这使得我们可以检查在容器内运行的应用程序,而不需要对任何容器或应用程序进行检测。检测在每个节点上进行,而不是针对每个Pod。
  4. 因此,使用单一的检测点,你就可以监控你的主机、网络、容器和应用程序——所有这些都使用Kubernetes元数据进行标记。您可以通过Kubernetes中的DaemonSet部署Sysdig。
  5. 然后,你可以根据你的要求,在Sysdig Monitor的云服务或我们的内部部署软件中对此数据进行可视化和报警。

基于此,Sysdig Monitor现在可以从以基础架构为中心和以应用为中心的角度提供丰富的可视性和上下文。 两全其美!

让我们来看看实际是什么样子。

按Kubernetes元数据分组

Sysdig Monitor的核心功能之一就是分组。你可以根据物理层次(例如,AWS region > Host > pod > container),或者基于逻辑微服务层次(例如,namespace > replicaset > pod > container)对容器进行分组和检索

未分类

未分类

如果你对利用你的基础物理资源感兴趣——例如识别noisy neighbors——那么物理层次是较好的选择。但是如果你正在研究应用程序和微服务的性能,那么逻辑层次往往是较好的。

一般来说,与典型Dashboard相比,动态重新组合基础架构的能力是解决环境故障更强大的方法。

分析Kubernetes服务的响应时间

例如:通过单击逻辑表中的Prod -> WordPress,我们会自动获得一个dashboard,不管容器中运行的是主机或数据中心服务,该dashboard可以分析所有容器上聚合的HTTP服务性能。其中一个强大的概况是服务响应时间:跨所有相关容器自动聚合服务延迟,然后将其与资源利用率相关联:

未分类

这使我们能够快速分析服务是否按预期执行,是否与底层资源利用率有关。 现在我们可以更深入服务。

分析Kubernetes HTTP服务的最慢端点

接下来,让我们深入应用程序本身的特定指标——在本演示中使用WordPress应用程序充当我们的HTTP服务,让我们来看看HTTP概况。

未分类

从上图你可以看到我们现在可以深入了解:

  • 最常用的HTTP端点
  • 最慢的HTTP端点
  • 平均连接时间
  • 错误
  • 状态码

实现此服务的Pod可能分散在多台计算机上,但我们仍然可以将此服务的请求计数、响应时间和URL统计信息汇总在一起。不要忘记:这不需要任何配置或检测WordPress、Apache或底层容器。

同样,如果这是RabbitMQ、MySQL、Redis、Consul、Nginx或其他50多个组件服务,我们将以相同的方式执行(尽管每个应用程序的指标会有所不同)。

关联Kubernetes事件

最后,根据你正在检测的任何metrics信息,查看Kubernetes汇报的上下文事件,可能会提供一些有用的线索用以查看你的应用程序的运行过程。Sysdig会自动收集Kubernetes事件,所以你可以这么做。

未分类

从这个视图(或任何其他方面),你可以轻松地为Kubernetes service聚合的metrics信息创建报警策略,而不是容器或node节点。此外,你仍然可以深入到任何单独的容器中进行深度检查直至进程级别。

可视化你的Kubernetes Services

上面的例子让你感受了如何监控一个Kubernetes service的性能。但是如果我们想看到我们所有的service,以及他们如何相互沟通呢?我们通过拓扑视图来完成这个任务。

下面的两张图片展示的是完全相同的基础设施和服务。第一张图描述了物理层次,一个master节点和三个node节点:

未分类

而第二张图将容器分组到Namespace、Service和Pod中,同时抽象容器的物理位置。

未分类

第二张(面向服务的)视图对于监视Kubernetes应用程序是多么自然和直观。应用程序的结构和各种依赖性非常清晰。各种微服务之间的交互变得明显,尽管这些微服务混合在我们的机器群集中!

视频:https://v.qq.com/x/page/c0602kmsnm8.html

总结

主要结论是:如果你有一个非常庞大的部署,你必须开始考虑用一种适合你的方式来监视Kubernetes集群环境。

kvm实战应用–kvm基础部署

虚拟化基本上是一个企业里边必不可少的一项技能了,但是测试环境当中,虚拟化又是很简单的。

一、安装KVM

1、验证CPU是否支持KVM;如果结果中有vmx(Intel)或svm(AMD)字样,就说明CPU的支持的。

egrep '(vmx|svm)' /proc/cpuinfo

未分类

2、关闭SELinux,防火墙等。

setenforce 0        #永久关闭修改配置文件
iptables -F
chkconfig iptables o
service NetworkManager stop
chkconfig NetworkManager off

3、如果是最小化安装的CentOS的话,那么有一些基础工具没有,可以先安装一下。

yum -y install epel-release net-tools vim unzip zip wget ftp

4、安装KVM及依赖

yum -y install qemu-kvm libvirt virt-install bridge-utils

5、验证安装结果

lsmod | grep kvm

未分类

6、开启KVM服务,设置开机自启

service libvirtd start
chkconfig libvirtd on

7、查看运行状态

service libvirtd status

未分类

8、配置网卡为网桥模式。配置前先备份一下网卡文件

A、创建ifcfg-br0文件,内容如下:

mkdir /backup
cp /etc/sysconfig/network-scripts/ /backup/ -a
cd /etc/sysconfig/network-scripts/
vim ifcfg-br0

DEVICE="br0"  
ONBOOT="yes"  
TYPE="Bridge"  
BOOTPROTO="static"  
IPADDR="192.168.96.10"    #这个就是服务器的IP地址
NETMASK="255.255.255.0"  
GATEWAY="192.168.96.100"  
DNS="192.168.96.101"  
#IPV6INIT="yes"  
#IPV6_AUTOCONF="yes"  
DHCPV6C="no"  
STP="on"  
DELAY="0"  

B、替换ifcfg-em1(就是服务器在用的第一个网卡)里边的内容为下边的

DEVICE=em1
ONBOOT=yes  
BRIDGE="br0"  

C、重启网络服务。

service network restart

然后ifconfig查看,发现多出了br0网卡,这个br0也成为了系统现在所使用的网卡。

未分类

二、安装虚拟机

1、准备操作系统安装所需的镜像文件

mkdir -p /home/kvm/ios

把想要安装的系统镜像拷到此目录之下。

2、创建虚拟机文件存放的目录

mkdir -p /home/kvm/image

3、直接创建虚拟机。这里先创建一个模板虚拟机,方便以后直接克隆使用,而不需要再重复安装系统

virt-install -name=centos7_2H4G --ram 4096 --vcpus=2 --disk path=/home/kvm/image/centos7_2H4G.img,size=200 --cdrom /home/kvm/ios/CentOS-7-x86_64-DVD-1611.iso --network bridge=br0 --graphics vnc,listen=0.0.0.0,port=6666,keymap=en_us --accelerate --force  --autostart  

事实上创建的时候名字用-n就可以了,但是我当时不知道,这样创建了一个名字为ame=centos7_2H4G的虚拟机,等会儿再说说给虚拟机改名的事儿。

简单说明下各选项的意义:

-n                        #指定创建虚拟机名称
--ram                     #指定内存大小
--vcpus                   #指定CPU个数
--disk path               #指定虚拟机文件存储名称及位置
size                      #指定虚拟机大小
--cdrom                   #指定镜像位置
--network bridge          #指定网桥
vnc,listen=0.0.0.0,port   #指定远程连接端口

4、直接远程连接安装操作系统

  1. 使用VNC进行远程连接,如果是初次使用vnc可能会有问题,解决办法网上难找,不过在另外一个地方有记录点我解决。
  2. 用IP+端口就能够登陆安装操作系统了。
  3. 有时候安装完之后重启,会有找不到系统盘的报错,这个暂时无解,把刚才的虚拟机删掉,重新创建咯。
  4. 装完操作系统,配置IP之类的,就可以直接远程连接使用了。

5、刚才的安装好系统,关机,作为模板文件

virsh shutdown ame=centos7_2H4G

6、使用模板克隆出一个新的虚拟机

virt-clone -o 原虚拟机 -n 新虚拟机 -f 新img文件
virt-clone  -o CentOS7_2H4G -n test -f /home/kvm/image/test.img
  1. 以模板为蓝本创建一个名为maopao(可自定义)的虚拟机,新虚拟机文件位置为。
  2. 创建完成之后,需要修改它的远程连接端口
virsh edit test
搜索/vnc
端口更改成另外一个,yes要改成no,这个如果不改,则无法使用。

未分类

7、启动新的虚拟机,vnc远程连接,可以设置IP了

virsh start test

在vnc中使用宿主机IP+端口的方式访问。

现在,一个虚拟机的使用创建流程就是这样。