jenkins实现PHP项目持续集成部署

安装jenkins相关依赖

wget -O /etc/yum.repos.d/jenkins.repo http://pkg.jenkins-ci.org/redhat/jenkins.repo
rpm --import https://jenkins-ci.org/redhat/jenkins-ci.org.key
yum install jenkins
yum install Java
yum install java-1.8.0-openjdk
yum install PHP
yum install php-devel
yum install php-pear
yum install re2c
yum install php-pear-phing

jenkins配置和启动

service jenkins start

输入localhost:8080即可访问。

插件安装

  • 系统管理-插件设置
  • 安装以下插件
  • Phing(php构建工具)
  • Publish Over SSH Plugin(通过ssh发布代码)

配置SSH免登录

假设有两台服务器。A为发布机,即jenkins所在机器。B为应用服务器,即运行PHP的服务器。

首先在A服务器生成公私钥。

ssh-keygen -t rsa

这时.ssh目录下会生成私钥和公钥的键值对id_rsa,id_rsa.pub

将id_rsa.pub公钥复制到B服务器上,并重命名为authorized_keys。

scp ~/.ssh/ras.pub root@B:/root/.ssh/authorized_keys

这时候ssh到B服务器则无需登录密码。

ssh root@B

注:若生成RSA密码的时候设置了ssh key,SSH到B服务器的时候还需要输入相应ssh key。

配置Publish Over SSH Plugin

系统管理—系统设置

未分类

  • Jenkins SSH Key:生成rsa的时候设置的ssh key,若没有设置则留空。
  • Key:填上A服务器私钥的内容。默认路径 ~/.ssh/id_rsa
  • Hosename:填上B服务器的IP
  • username:填上B服务器的帐号

配置phing build.xml

进入当前job的项目目录

cd /var/lib/jenkins/workspace/Git

未分类

build.xml文件内容如下

<?xml version="1.0" encoding="UTF-8"?>
<project name="api" default="build">
        <target name="build" depends="make_runtime,check,tar"/>
        <property name="version-m"  value="1.1" />
        <property name="version"    value="1.1.0" />
        <property name="stability"  value="stable" />
        <property name="releasenotes" value="" />
        <property name="tarfile"     value="${phing.project.name}.${buildnumber}.${buildid}.tar.gz" />
        <property name="pkgfile"     value="${phing.project.name}.${version}.tgz" />
        <property name="distfile"    value="dist/${tarfile}" />
        <property name="tests.dir" value="test" />
        <fileset id="api.tar.gz" dir=".">
            <include name="test/**"/>
            <include name="*.php"/>
            <include name="*.xml"/>
        </fileset>
        <target name="make_runtime">
                <mkdir dir="${project.basedir}/Runtime" />
                <mkdir dir="${project.basedir}/build/logs" />
                <mkdir dir="${project.basedir}/build/pdepend" />
                <mkdir dir="${project.basedir}/build/code-browser" />
        </target>

        <target name="check" description="Check variables" >
            <fail unless="version" message="Version not defined!" />
            <fail unless="buildnumber" message="buildnumber not defined!" />
            <fail unless="buildid" message="buildid not defined!" />
            <delete dir="dist" failonerror="false" />
            <mkdir dir="dist" />
        </target>

        <target name="tar" depends="check" description="Create tar file for release">
            <echo msg="Creating distribution tar for ${phing.project.name} ${version}"/>
            <delete file="${distfile}" failonerror="false"/>
            <tar destfile="${distfile}" compression="gzip">
                <fileset refid="api.tar.gz"/>
            </tar>
        </target>
</project>

这里我们只做简单发布,没有加入php-unit等插件。

开始构建项目

新建—输入项目名称,选择构建自由风格的软件项目—下一步

配置源码管理

这里我们用的是git

未分类

增加构建步骤,选择Invoke Phing targets,再新增一个构建步骤,选择Send files or execute commands over SSH

未分类

Phing targets配置如下

未分类

Send files or execute commands over SSH 配置如下

未分类

Source files:dist/api.${BUILD_NUMBER}.${BUILD_ID}.tar.gz
Remove prefix:dist/
Remote directory: /home/data/
Exec command:
mkdir -p /home/data/
mkdir-p /home/www/
cd /home/data/
tar -zxf api.${BUILD_NUMBER}.${BUILD_ID}.tar.gz -C /home/www/
  • /home/data/ 为B服务器接收打包文件的目录
  • /home/www/ 为B服务器PHP项目运行的目录

保存即可。

接下来进入项目–立即构建,完成后我们进入B服务器。

cd /home/data

未分类

至此已经大功搞成了。

一步步手工搭建etcd集群

目标

搭建一套三节点的 etcd 高可用集群

资源准备

  • 准备三台 Linux 服务器
192.168.9.1

192.168.9.2

192.168.9.3
  • 下载 etcd-v3.2.5

  • etcd:由于 raft 算法的特性,集群的节点数必须是奇数

服务器初始化

  • 三台服务器分别创建 etcd 用户并指定 gid 为:etcd

etcd 集群配置

  • 分别在三台服务器创建 conf、data、bin 目录:
etcd@XXXX$ mkdir -p /home/etcd/{conf,data,bin}
  • 将 etcd-v3.2.5-linux-amd64.tar.gz 分别上传至三台服务器中,解压后将 etcdctl、etcd 复制到 /home/etcd/bin 目录下,并将 /home/etcd/bin 目录配置到系统环境变量下

  • 三台服务器分别编辑 systemd 启动文件:

使用 root 用户编辑: vi /usr/lib/systemd/system/etcd.service
[Unit]
Description=Etcd Server
After=network.target
After=network-online.target
Wants=network-online.target

[Service]
Type=notify
WorkingDirectory=/home/etcd/data
EnvironmentFile=-/home/etcd/conf/etcd.conf
User=etcd
ExecStart=/bin/bash -c "GOMAXPROCS=$(nproc) /home/etcd/bin/etcd 
  --name ${ETCD_NAME} 
  --initial-advertise-peer-urls ${ETCD_INITIAL_ADVERTISE_PEER_URLS} 
  --listen-peer-urls ${ETCD_LISTEN_PEER_URLS} 
  --listen-client-urls ${ETCD_LISTEN_CLIENT_URLS},http://127.0.0.1:2379 
  --advertise-client-urls ${ETCD_ADVERTISE_CLIENT_URLS} 
  --initial-cluster-token ${ETCD_INITIAL_CLUSTER_TOKEN} 
  --initial-cluster ${ETCD_CLUSTER_ADDRESS} 
  --initial-cluster-state new 
  --data-dir=${ETCD_DATA_DIR}"
Restart=on-failure
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target
  • 通过 etcd 用户编辑 etcd 的启动参数文件:
vi /home/etcd/conf/etcd.conf
  • 规划三个节点 etcd name 分别为:etcd1、etcd2、etcd3

  • 下列配置文件内容中包含中文处需要根据当前服务器实际信息进行修改,ETCD_CLUSTER_ADDRESS 的值也要根据自己实际的 IP 就行修改,切记请勿直接 copy 后就立即使用

# [member]
ETCD_NAME=当前节点的etcd name,例如:etcd1
ETCD_DATA_DIR="/home/etcd/data"
ETCD_LISTEN_PEER_URLS="http://当前服务器IP:2380"
ETCD_LISTEN_CLIENT_URLS="http://当前服务器IP:2379"
#ETCD_WAL_DIR=""
#ETCD_SNAPSHOT_COUNT="10000"
#ETCD_HEARTBEAT_INTERVAL="100"
#ETCD_ELECTION_TIMEOUT="1000"
#ETCD_MAX_SNAPSHOTS="5"
#ETCD_MAX_WALS="5"
#ETCD_CORS=""

#[cluster]
ETCD_INITIAL_ADVERTISE_PEER_URLS="http://当前服务器IP:2380"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
ETCD_ADVERTISE_CLIENT_URLS="http://当前服务器IP:2379"
ETCD_CLUSTER_ADDRESS="etcd1=http://192.168.9.1:2380,etcd2=http://192.168.9.2:2380,etcd3=http://192.168.9.3:2380"

#ETCD_INITIAL_ADVERTISE_PEER_URLS="http://localhost:2380"
# if you use different ETCD_NAME (e.g. test), set ETCD_INITIAL_CLUSTER value for this name, i.e. "test=http://..."
#ETCD_INITIAL_CLUSTER="default=http://localhost:2380"
#ETCD_INITIAL_CLUSTER_STATE="new"
#ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
#ETCD_ADVERTISE_CLIENT_URLS="http://localhost:2379"
#ETCD_DISCOVERY=""
#ETCD_DISCOVERY_SRV=""
#ETCD_DISCOVERY_FALLBACK="proxy"
#ETCD_DISCOVERY_PROXY=""
#ETCD_STRICT_RECONFIG_CHECK="false"
#ETCD_AUTO_COMPACTION_RETENTIO:N="0"
#
#[proxy]
#ETCD_PROXY="off"
#ETCD_PROXY_FAILURE_WAIT="5000"
  • 通过 systemctl 启动 etcd,分别在三台服务器上通过 root 组用户执行:
systemctl daemon-reload
systemctl start etcd
  • 集群健康状态检测

任意一台服务器上通过 etcd 用户执行:etcdctl cluster-health
如果三个节点状态都是 is healthy,证明 etcd 集群搭建完毕。

怎么利用wget下载文件并保存到指定目录

资源下载的尴尬时刻

有时候人在天朝确实好难下载到墙外的资源(抓头发),好比说我今天忍不住买了一个付费插件,挂了V P N下载,愣是一直卡在0.1MB/6MB,更要命的是有时卡在95%/100%,然而开google网页秒开,无解……

未分类

郁闷了几分钟,想说可不可以通过服务器(前提你得有个服务器)下载到资源,再把资源用FTP下载到本地电脑,嗯可行,百度下,该文详述了服务器指令wget的详细用法(http://java-er.com/blog/wget-useage-x/),我只需用下面这个,记录下:

wget是Linux上一个非常不错的下载指令,一般来说,要使用wget下载档案,只需要打以下的指令:

wget 网址

而要让档案自动储存到指令的目录下,则需要借用-P这个参数,可以使用以下的指令

wget -P 目录 网址

举例来说,如果你要放到/root底下,你可以打下列的指令:

wget -P /root 网址

利用wget下载文件并保存到指定目录

炒鸡简单,套用“wget -P 目录 网址”指令齐全如下:

wget -P /root https://yoast-mercury.s3.amazonaws.com/uploads/edd/2017/07/wordpress-seo-premium-5.0.2.zip

指令核对清楚后,点击enter执行,就可以看到代码行在跑了,如下文和下图所示:

[root@xxxxxx ~]# wget -P /root https://yoast-mercury.s3.amazonaws.com/uploads/edd/2017/07/wordpress-seo-premium-5.0.2.zip
--2017-07-24 11:31:44-- https://yoast-mercury.s3.amazonaws.com/uploads/edd/2017/07/wordpress-seo-premium-5.0.2.zip
Resolving yoast-mercury.s3.amazonaws.com... 52.216.227.120
Connecting to yoast-mercury.s3.amazonaws.com|52.216.227.120|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 6744136 (6.4M) [application/zip]
Saving to: ?.root/wordpress-seo-premium-5.0.2.zip.1?

100%[===============================================================>] 6,744,136 285K/s in 59s (平均速度285K每秒,59秒下载完毕!)

2017-07-24 11:32:43 (112 KB/s) - ?.root/wordpress-seo-premium-5.0.2.zip.1?.saved [6744136/6744136]

未分类

打开FTP工具,可以看到资源已经下载到指定的服务器目录底下了!右击传输到自己的本地电脑即可:)

终于拿到了付费插件,心情是激动的:

未分类

如何知道资源的下载网址?

一般用chrome浏览器,下载失败后会提示,举个例子,如图:

未分类

  • AhrefsTop-24-Jul-27831f24679b5143712800002a891b96.csv 已取消
  • https://ahrefs.com/download/2017-07-24/csv/AhrefsTop-24-Jul-27831f24679b5143 (这个网址就是下载地址啦,但是它最后的文件名不完整,把第一行的文件名代入即可啦)

补全后,完整的下载地址就是这样子啦:https://ahrefs.com/download/2017-07-24/csv/AhrefsTop-24-Jul-27831f24679b5143712800002a891b96.csv

  • 资料大小;25M
  • 下载速度:3.02M每秒
  • 下载时间:7.4秒
[root@xxxxxxxxxx ~]# wget -P /root https://ahrefs.com/download/2017-07-24/csv/AhrefsTop-24-Jul-27831f24679b5143712800002a891b96.csv
--2017-07-24 11:05:30-- https://ahrefs.com/download/2017-07-24/csv/AhrefsTop-24-Jul-27831f24679b5143712800002a891b96.csv
Resolving ahrefs.com... 151.80.39.61
Connecting to ahrefs.com|151.80.39.61|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 26285637 (25M) [text/csv]
Saving to: ?.root/AhrefsTop-24-Jul-27831f24679b5143712800002a891b96.csv?

100%[=========================================================>] 26,285,637 3.02M/s in 7.4s

2017-07-24 11:05:38 (3.40 MB/s) - ?.root/AhrefsTop-24-Jul-27831f24679b5143712800002a891b96.csv?.saved [26285637/26285637]

以后可以愉快地玩耍了。

设置curl和wget使用http https代理

Linux Shell 提供两个非常实用的命令来爬取网页,它们分别是 curl 和 wget

curl 和 wget 使用代理

  • curl 支持 http、https、socks4、socks5

  • wget 支持 http、https

代理示例:

#!/bin/bash
#
# curl 支持 http、https、socks4、socks5
# wget 支持 http、https
#


# http代理格式         http_proxy=http://IP:Port
# https代理格式         https_proxy=http://IP:Port

{'http': 'http://120.77.176.179:8888'}
curl -m 30 --retry 3 -x http://120.77.176.179:8888 http://proxy.mimvp.com/exist.php                    # http_proxy
wget -T 30 --tries 3 -e "http_proxy=http://120.77.176.179:8888" http://proxy.mimvp.com/exist.php          # http_proxy

{'https': 'http://46.105.214.133:3128'}
curl -m 30 --retry 3 --proxy-insecure -x http://46.105.214.133:3128 -k https://proxy.mimvp.com/exist.php                    # https_proxy
wget -T 30 --tries 3 --no-check-certificate -e "https_proxy=http://46.105.214.133:3128" https://proxy.mimvp.com/exist.php    # https_proxy


# curl  支持socks
{'socks4': '101.255.17.145:1080'}
curl -m 30 --retry 3 --socks4 101.255.17.145:1080 http://proxy.mimvp.com/exist.php

{'socks5': '82.164.233.227:45454'}
curl -m 30 --retry 3 --socks5 82.164.233.227:45454 http://proxy.mimvp.com/exist.php


# wget 不支持socks

wget 配置文件设置代理

vim ~/.wgetrc

http_proxy=http://120.77.176.179:8888:8080
https_proxy=http://12.7.17.17:8888:8080
use_proxy = on
wait = 30

wget -T 30 --tries 3 http://proxy.mimvp.com

Shell 设置临时局部代理

# proxy no auth
export http_proxy=http://120.77.176.179:8888:8080
export https_proxy=http://12.7.17.17:8888:8080

# proxy auth
export http_proxy=http://username:[email protected]:8888:8080
export https_proxy=http://username:[email protected]:8888:8080


# 取消设置
unset http_proxy
unset https_proxy

Shell 设置系统全局代理

# 修改 /etc/profile,保存并重启服务器
sudo vim /etc/profile        # 所有人有效
或
sudo vim ~/.bashrc        # 所有人有效
或
vim ~/.bash_profile        # 个人有效


# proxy no auth
export http_proxy=http://120.77.176.179:8888:8080
export https_proxy=http://12.7.17.17:8888:8080

# proxy auth
export http_proxy=http://username:[email protected]:8888:8080
export https_proxy=http://username:[email protected]:8888:8080

source /etc/profile
或
source ~/.bashrc
或
source ~/.bash_profile


sudo reboot

CentOS 6安装Sendmail Dovecot Squirrelmail邮件系统

本文记录在本地虚拟机CentOS6上搭建Sendmail + Dovecot + Squirrelmail 的Webmail环境的过程,仅仅是本地局域网的环境测试,不配置DNS, 也没有安全认证,Squirrelmail 版本squirrelmail-webmail-1.4.22。

前言

关于CentOS系统的安装,这里便不做介绍了,大家可以在网上找到很多相关的资料参考。如果已经对下面的命令熟悉的朋友,请直接跳到下一步…

现简单介绍一下一些基本命令的使用:

1、查看系统发行版本

[lz@localhost ~]$ cat /etc/issue
CentOS release 6.9 (Final)
Kernel r on an m

2、查看内核版本

[lz@localhost ~]$ uname -a
Linux localhost.localdomain 2.6.32-71.el6.x86_64 #1 SMP Fri May 20 03:51:51 BST 2011 x86_64 x86_64 x86_64 GNU/Linux

3、获取系统权限

[lz@localhost ~]$ su root      
Password:             【输入lz的密码】
[root@localhost lz]# 

4、让用户能获取root权限

[root@localhost lz]# vim /etc/sudoers

未分类

按esc键,输入:wq! 保存文件,退出,这样lz就用使用sudo命令获取root权限了。来,试试看。

[root@localhost lz]# exit
exit
[lz@localhost ~]$ sudo -i     【获取root权限】
We trust you have received the usual lecture from the local System
Administrator. It usually boils down to these three things:
    #1) Respect the privacy of others.
    #2) Think before you type.
    #3) With great power comes great responsibility.
[sudo] password for lz: 
[root@localhost ~]# 

5、修改主机名和hosts文件

[root@mail ~]# cat /etc/sysconfig/network
NETWORKING=yes
NETWORKING_IPV6=no
HOSTNAME=mail.squirrelmail.com
[root@mail ~]# cat /etc/hosts
127.0.0.1 mail.squirrelmail.com localhost.localdomain
127.0.0.1 squirrelmail.com  localhost.localdomain
127.0.0.1 localhost.localdomain localhost
::1 localhost6.localdomain6 localhost6

重启一下系统,命令提示符前面的就会变成如上所示。

6、更新系统

[root@mail ~]# yum update

这个过程可能需要比较长的时间,耐心等待系统更新完成。

一、Sendmail安装和配置

下面记录Sendmail的安装过程,重要的步骤会给出命令行输出结果。首先,我们需要安装一些依赖包,CentOS系统使用yum来安装,跟Debian/Ubuntu的apt-get 类似可以很方便的安装一些软件。press y

[root@mail mail]# yum install m4 telnet mailx
Loaded plugins: fastestmirror, refresh-packagekit
Setting up Install Process
Loading mirror speeds from cached hostfile
* base: centos.ustc.edu.cn
* extras: centos.ustc.edu.cn
* updates: centos.ustc.edu.cn
Package m4-1.4.13-5.el6.x86_64 already installed and latest version
Package 1:telnet-0.17-48.el6.x86_64 already installed and latest version
Package mailx-12.4-8.el6_6.x86_64 already installed and latest version
Nothing to do

1、Sendmail安装

[root@mail mail]# yum install sendmail sendmail-cf
Loaded plugins: fastestmirror, refresh-packagekit
Setting up Install Process
Loading mirror speeds from cached hostfile
* base: centos.ustc.edu.cn
* extras: centos.ustc.edu.cn
* updates: centos.ustc.edu.cn
Package sendmail-8.14.4-9.el6_8.1.x86_64 already installed and latest version
Package sendmail-cf-8.14.4-9.el6_8.1.noarch already installed and latest version
Nothing to do

我这已经安装好了,仅演示安装过程,在软件的安装过程中,会提示输入[y/N] : y , 当然输入y了

2、Sendmail配置

Sendmail的配置文件默认是在/etc/mail目录下的:

[root@mail mail]# ls /etc/mail
access     aliasesdb-stamp  domaintable.db  local-host-names  mailertable.db  Makefile     sendmail.cf.bak  submit.cf  trusted-users  virtusertable.db
access.db  domaintable      helpfile        mailertable       make            sendmail.cf  sendmail.mc      submit.mc  virtusertable

默认监听的是本地接口地址: 127.0.0.1:25, 我们可以通过命令查看

[root@mail mail]# ps -ef | grep -v grep | grep -i sendmail
root      29409      1  0 14:52 ?        00:00:00 sendmail: accepting connections
smmsp     29419      1  0 14:52 ?        00:00:00 sendmail: Queue runner@01:00:00 for /var/spool/clientmqueue
[root@mail mail]# netstat -an | grep :25 | grep tcp
tcp        0      0 127.0.0.1:25                0.0.0.0:*                   LISTEN

如果要让Sendmail监听本机的所有接口地址,可以修改sendmail.mc文件, 如果默认监听的是0.0.0.0:25,则可以跳过下面这步。

[root@mail mail]# vim /etc/mail/sendmail.mc
大概在116行, 将如下内容注释掉, 在行首添加dnl
From:
DAEMON_OPTIONS(`Port=smtp,Addr=127.0.0.1, Name=MTA')dnl

To:
dnl # DAEMON_OPTIONS(`Port=smtp,Addr=127.0.0.1, Name=MTA')dnl

重启一下Sendmail,再查看:

[root@mail ~]# service sendmail restart
Shutting down sm-client:                                   [  OK  ]
Shutting down sendmail:                                    [  OK  ]
Starting sendmail:                                         [  OK  ]
Starting sm-client:                                        [  OK  ]
[root@mail ~]# netstat -an | grep :25 | grep tcp
tcp        0      0 0.0.0.0:25                  0.0.0.0:*                   LISTEN 

下面将使用m4这个工具来创建sendmail.cf这个文件

[root@mail ~]# m4 /etc/mail/sendmail.mc > /etc/mail/sendmail.cf

在local-host-names增加域名项,表示的是可以用来发送/接收邮件的域名。

[root@mail ~]# cat /etc/mail/local-host-names 
# local-host-names - include all aliases for your machine here.
squirrelmail.com
mail.squirrelmail.com

重启Sendmail,设置开机启动。

[root@mail ~]# service sendmail restart
Shutting down sm-client:                                   [  OK  ]
Shutting down sendmail:                                    [  OK  ]
Starting sendmail:                                         [  OK  ]
Starting sm-client:                                        [  OK  ]
[root@mail ~]# chkconfig sendmail on      【开机启动】

3、Sendmail发送邮件测试: mail命令测试

首先创建两个测试的账户: 使用useradd命令添加两个用户user1和user2、然后用passwd命令更改密码、再将用户添加到mail组。

[root@mail ~]# useradd user1      【添加用户】
[root@mail ~]# useradd user2
[root@mail ~]# passwd user1       【修改密码】
Changing password for user user1.
New password: 
BAD PASSWORD: it does not contain enough DIFFERENT characters
BAD PASSWORD: is too simple
Retype new password: 
passwd: all authentication tokens updated successfully.
[root@mail ~]# passwd user2       【修改密码】
Changing password for user user2.
New password: 
BAD PASSWORD: it does not contain enough DIFFERENT characters
BAD PASSWORD: is too simple
Retype new password: 
passwd: all authentication tokens updated successfully.
[root@mail ~]# gpasswd -a user1 mail    【添加用户到mail组】
Adding user user1 to group mail
[root@mail ~]# gpasswd -a user2 mail
Adding user user2 to group mail

用其中一个账户登陆,给另一个用户发送邮件

[root@mail ~]# su user1      【切换用户user1】      
[user1@mail root]$ mail -s "hello user2" user2      [发送邮件:mail -s "主题内容" "收信人"]
This is a test mail from user1.               【邮件正文】               
.
EOT
[user1@mail root]$ exit
exit
[root@mail ~]# cat /var/mail/user2             【查看邮件】
From [email protected]  Wed Aug  9 17:18:16 2017
Return-Path: <[email protected]>
Received: from mail.squirrelmail.com (mail.squirrelmail.com [127.0.0.1])
    by mail.squirrelmail.com (8.14.4/8.14.4) with ESMTP id v799IFCn003225
    for <[email protected]>; Wed, 9 Aug 2017 17:18:16 +0800
Received: (from user1@localhost)
    by mail.squirrelmail.com (8.14.4/8.14.4/Submit) id v799IFjw003224
    for user2; Wed, 9 Aug 2017 17:18:15 +0800
From: [email protected]
Message-Id: <[email protected]>
Date: Wed, 09 Aug 2017 17:18:15 +0800
To: [email protected]
Subject: hello user2
User-Agent: Heirloom mailx 12.4 7/29/08
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

This is a test mail from user1.

可以看到,上面的邮件发送成功。

[说明] 使用mail命令发送邮件, “-s”后面接邮件主题,然后是接收邮件的账户,直接使用用户名即可,在本域测试。然后输入邮件正文,最后用’.’ ,表示邮件正文结束。

4、Sendmail发送邮件测试: telnet方式测试

未分类

5、防火墙设置

需要设置防火墙允许本机25号端口的数据通过:

[root@starnight mail]# iptables -A INPUT -p tcp -m tcp --dport 25 -j ACCEPT

保存防火墙设置,并重启:

[root@starnight mail]# service iptables save      【保存设置】
iptables: Saving firewall rules to /etc/sysconfig/iptables:[  OK  ]
[root@starnight mail]# service iptables restart    【重启防火墙】
iptables: Setting chains to policy ACCEPT: filter          [  OK  ]
iptables: Flushing firewall rules:                         [  OK  ]
iptables: Unloading modules:                               [  OK  ]
iptables: Applying firewall rules:                         [  OK  ]
[root@starnight mail]# service iptables stop      【关闭,我比较暴力】
iptables: Setting chains to policy ACCEPT: filter          [  OK  ]
iptables: Flushing firewall rules:                         [  OK  ]
iptables: Unloading modules:                               [  OK  ]
[root@starnight mail]#  

到这里,Sendmail的配置就完成了。成功!

二、Dovecot 安装配置

需要先安装一些依赖包:

[root@mail ~]# yum install telnet mailx mutt

1、Dovecot安装

[root@mail ~]# yum install dovecot

2、Dovecot配置

默认情况下,Dovecot的配置文件在/etc/dovecot/下

[root@mail ~]# ls /etc/dovecot/
conf.d  dovecot.conf

修改配置文件/etc/dovecot/dovecot.conf:

[root@mail ~]# vim /etc/dovecot/dovecot.conf

去掉protocols的注释, 即去掉’#’

未分类

打开配置文件/etc/dovecot/conf.d/10-mail.conf:

[root@mail ~]# vim /etc/dovecot/conf.d/10-mail.conf

设置:mail_location = mbox:~/mail:INBOX=/var/mail/%u

未分类

启动和查看Dovecot 服务:

[root@mail ~]# service dovecot start
Starting Dovecot Imap:                                     [  OK  ]
[root@mail ~]# ps -ef | grep -v grep | grep -i dovecot
root       3556      1  0 17:42 ?        00:00:00 /usr/sbin/dovecot
dovecot    3558   3556  0 17:42 ?        00:00:00 dovecot/anvil
root       3559   3556  0 17:42 ?        00:00:00 dovecot/log
root       3561   3556  0 17:42 ?        00:00:00 dovecot/config
[root@mail ~]# netstat -planet | grep -i dove
tcp        0      0 0.0.0.0:993                 0.0.0.0:*                   LISTEN      0          21510      3556/dovecot        
tcp        0      0 0.0.0.0:995                 0.0.0.0:*                   LISTEN      0          21502      3556/dovecot        
tcp        0      0 0.0.0.0:110                 0.0.0.0:*                   LISTEN      0          21500      3556/dovecot        
tcp        0      0 0.0.0.0:143                 0.0.0.0:*                   LISTEN      0          21508      3556/dovecot        
tcp        0      0 :::993                      :::*                        LISTEN      0          21511      3556/dovecot        
tcp        0      0 :::995                      :::*                        LISTEN      0          21503      3556/dovecot        
tcp        0      0 :::110                      :::*                        LISTEN      0          21501      3556/dovecot        
tcp        0      0 :::143                      :::*                        LISTEN      0          21509      3556/dovecot 

3、Dovecot接收邮件测试: mutt

之前在测试Sendmail的时候,用user1这个账户向user2发送了一封邮件,通过查看本地文件进行验证。

[root@mail ~]# mutt -f imap://user2:123456@localhost              【用户user2  密码:123456】

第一次使用在底部会有提示,按照提示进行即可:

未分类
yes

未分类
a

accept 之后,会出现如下邮件列表,

未分类

按回车键即可查看邮件:

未分类

【注】如果新建的用户user1或user2没有加入到mail用户组,通过这种方式查看邮件就会出错。

4、Dovecot接收邮件测试: telnet方式测试

未分类

到这里,Dovecot的配置就完成了。成功!

三、Squirrelmail安装

1、配置Web环境

CentOS Apache2默认应该是安装了的,名称为httpd,如果没有安装可以采用如下命令进行安装

安装:

[root@mail html]# yum install httpd

启动、停止、重启等命令:

[root@mail html]# service httpd start
Starting httpd:                                            [  OK  ]
[root@mail html]# service httpd stop
Stopping httpd:                                            [  OK  ]
[root@mail html]# service httpd restart
Stopping httpd:                                            [  OK  ]
Starting httpd:                                            [  OK  ]

此刻访问虚拟机ip地址,应该就能正常访问了

未分类

2、安装PHP

安装方法也很简单:

[root@mail html]# yum install php

测试: 在web根目录:/var/www/html, 编写如下文件info.php

[root@mail html]# pwd
/var/www/html
[root@mail html]# cat info.php 
<?php
phpinfo();
?>

浏览器访问:http://192.168.1.103/info.php

未分类

3、下载和配置Squirrelmail

下载:

切换到web根目录:使用如下命令下载

[root@mail html]# wget https://nchc.dl.sourceforge.net/project/squirrelmail/stable/1.4.22/squirrelmail-webmail-1.4.22.tar.gz

未分类

解压:

[root@mail html]# tar -zxvf squirrelmail-webmail-1.4.22.tar.gz 
[root@mail html]# ls
info.php  squirrelmail-webmail-1.4.22  squirrelmail-webmail-1.4.22.tar.gz
[root@mail html]# mv squirrelmail-webmail-1.4.22 squirrelmail            【重命名为squirrelmail】
[root@mail html]# ls
info.php  squirrelmail  squirrelmail-webmail-1.4.22.tar.gz
[root@mail html]# cd squirrelmail
[root@mail squirrelmail]# ls
class  config  configure  contrib  data  doc  functions  help  images  include  index.php  locale  plugins  po  README  src  themes
[root@mail squirrelmail]# cd config
[root@mail config]# ls
config_default.php  config_local.php  conf.pl  index.php

配置:

运行配置文件:

[root@mail config]# pwd
/var/www/html/squirrelmail/config
[root@mail config]# ls
config_default.php  config_local.php  conf.pl  index.php
[root@mail config]# ./conf.pl         【运行配置文件】

配置项如下:

未分类

修改一下域名:可以根据自己的需求进行相应的修改。

[2].  Server Settings  => [1].  Domain  => 输入:mail.squirrelmail.com  => 输入:S  [保存数据] =>  输入:R [返回上一级]  => Q [退出]

4、测试和修改

浏览器访问:http://192.168.1.103/squirrelmail/src/configtest.php

未分类

看到上面出现两个错误,我们可以尝试解决一下:

  • PHP short_open_tag = off 需要设置为On

[root@mail html]# vim /etc/php.ini

未分类

  • 在填加两个文件夹data和attach,并赋予写权限
[root@mail ~]# cd /var/local/
[root@mail local]# ls
[root@mail local]# mkdir squirrelmail
[root@mail local]# cd squirrelmail/
[root@mail squirrelmail]# mkdir data
[root@mail squirrelmail]# mkdir attach
[root@mail squirrelmail]# chmod a+w data/
[root@mail squirrelmail]# chmod a+w attach/
[root@mail squirrelmail]# ls -l
total 8
drwxrwxrwx 2 root root 4096 Aug  9 21:39 attach
drwxrwxrwx 2 root root 4096 Aug  9 21:39 data 

重启一下Web服务器: httpd

[root@mail squirrelmail]# service httpd restart

再次访问正常:

未分类

5、登陆Squirrelmail 和邮件发送、接收测试

现在可以访问: http://192.168.1.103/squirrelmail/src/login.php

未分类

用之前新建的账户名: user1/user2 : 123456 登陆, 用user2登陆看看,可以发现已经有一封之前发送的邮件了

未分类

下面我们在Webmail中发送邮件试试:user2 发送给 user1

未分类

再用user1登陆看看, 可以看到我们刚才发送的测试邮件…

未分类

至此,我们在CentOS6 上安装 Sendmail + Dovecot + Squirrelmail 圆满成功。

【注】不得不提的是,这只是个局域网的Webmail的测试环境,如果要实际使用的话,还必须搭建一个DNS服务器,还有跟邮件服务器配套的相关垃圾邮件过滤,认证之类的。

ngx_http_mirror_module- nginx流量镜像模块用法

Nginx 1.13.4版本新增了ngx_http_mirror_module模块。

ngx_http_mirror_module模块适用于这样一种场景,可以把真实请求引流到测试环境。

配置示例

location / {

    mirror /mirror;

    proxy_pass http://backend;

}


location /mirror {

    internal;

    proxy_pass http://test_backend$request_uri;

}

配置两组后台服务器,http://backend指向生产服务器, http://test_backend指向测试服务器。

用户访问生产服务器的同时,请求会被nginx复制发送给测试服务器,需要注意的一点是mirror不会输出http返回内容。

Nginx流量拷贝ngx_http_mirror_module模块配置及分析

一、背景

最近nginx官网公布了nginx1.13.4最新的ngx_http_mirror_module模块,利用mirror模块,业务可以将线上实时访问流量拷贝至其他环境,基于这些流量可以做版本发布前的预先验证,进行流量放大后的压测等等。本着兴趣笔者调研了其实现原理和使用方式,通过demo的形式展示给读者,希望能解决大家在使用过程中遇到的问题。

二、mirror模块配置

mirror模块配置分为两部分,源地址和镜像地址配置,配置位置可以为nginx配置文件的http, server, location上下文,配置示例为:

# original配置
location / {
    mirror /mirror;
    mirror_request_body off;
    proxy_pass http://127.0.0.1:9502;
}

# mirror配置
location /mirror {
    internal;
    proxy_pass http://127.0.0.1:8081$request_uri;
    proxy_set_header X-Original-URI $request_uri;
}

1、original配置

  • location /指定了源uri为/

  • mirror /mirror指定镜像uri为/mirror

  • mirror_request_body off | on 指定是否镜像请求body部分,此选项与proxy_request_buffering、fastcgi_request_buffering、scgi_request_buffering和 uwsgi_request_buffering冲突,一旦开启mirror_request_body为on,则请求自动缓存;

  • proxy_pass 指定上游server的地址

2、mirror配置

  • internal 指定此location只能被“内部的”请求调用,外部的调用请求会返回”Not found” (404)

  • proxy_pass 指定上游server的地址

  • proxy_set_header 设置镜像流量的头部

未分类

按照上述配置,搭建了上图所示的验证环境,各个模块均部署在本机,由curl发起请求:

curl 127.0.0.1

original和mirror均为上游server PHP脚本,其中original返回响应response to client。 抓包结果如下图:

未分类

分析抓包结果,整个请求流程为:

  • curl向nginx 80端口发起GET / HTTP请求

  • nginx将请求转发至upstream 9502端口的original php脚本,nginx本地端口为51637

  • nginx将请求镜像发至upstream 8081端口的mirror PHP脚本,nginx本地端口为51638

  • original发送响应response to client至nginx

  • nginx将响应转发至curl,curl将响应展示到终端

  • mirror将响应发送至nginx,nginx丢弃。

由此可见,在整个流程中,nginx将请求转发送至original和mirror,然后等待响应,几乎不会对正常请求造成影响,整个处理过程是完全异步的。

三、mirror模块实现

static ngx_int_t
ngx_http_mirror_handler_internal(ngx_http_request_t *r)
{
    ngx_str_t                   *name;
    ngx_uint_t                   i;
    ngx_http_request_t          *sr;
    ngx_http_mirror_loc_conf_t  *mlcf;

    mlcf = ngx_http_get_module_loc_conf(r, ngx_http_mirror_module);

    name = mlcf->mirror->elts;

    for (i = 0; i < mlcf->mirror->nelts; i++) {
        if (ngx_http_subrequest(r, &name[i], &r->args, &sr, NULL,
                                NGX_HTTP_SUBREQUEST_BACKGROUND)
            != NGX_OK)
        {
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }

        sr->header_only = 1;
        sr->method = r->method;
        sr->method_name = r->method_name;
    }

    return NGX_DECLINED;
}

nginx有关mirror的代码位于文件src/http/modules/ngx_http_mirror_module.c文件,上述为文件中的ngx_http_mirror_handler_internal函数。在开启了mirror之后此函数会被执行,可见其内部主要通过ngx_http_subrequest发起http子请求来实现的。

通过代码可见,nginx支持配置多个mirror uri,示例为:

location / {
    mirror /mirror;
    mirror /mirror2;
    mirror_request_body off;
    proxy_pass http://127.0.0.1:9502;
}

location /mirror {
    internal;
    proxy_pass http://127.0.0.1:8081$request_uri;
}

location /mirror2 {
    internal;
    proxy_pass http://127.0.0.1:8081$request_uri;
}

如何使用Bash解析nginx.conf中server_name的第一个域名

问题

在指定的nginx.conf vhost配置文件中,如何获取server_name变量的第一个域名?
vhosts配置文件是与nginx.conf分离的,通过include引入,现在我能使用grep显示server_name的行内容,不过我仅想要第一个域名。
所以,如果我执行grep “server_name” /each/vhost/conf,将输出:

root@getyou:/home# grep "server_name" /home/site-configs/getyou
        server_name getyou.onl;
        server_name www.getyou.onl getme.onl www.getme.onl;
root@getyou:/home# grep "server_name" /home/site-configs/kevinpirnie
        server_name kevinpirnie.com www.kevinpirnie.com;
root@getyou:/home# grep "server_name" /home/site-configs/airsweepinc
        server_name airsweepinc.com www.airsweepinc.com;
root@getyou:/home# grep "server_name" /home/site-configs/themedepot
        server_name theme-depot.net www.theme-depot.net;

而我想输入下面的:

root@getyou:/home# grep "server_name" /home/site-configs/getyou
        getyou.onl
root@getyou:/home# grep "server_name" /home/site-configs/kevinpirnie
        kevinpirnie.com
root@getyou:/home# grep "server_name" /home/site-configs/airsweepinc
        airsweepinc.com
root@getyou:/home# grep "server_name" /home/site-configs/themedepot
        theme-depot.net

最佳答案

使用GNU grep和Perl正则:

$ grep -m1 -Poe 'server_name K[^; ]+' getyou
getyou.onl

(-m1 仅获取第一个匹配,-P Perl正则,-o 只打印匹配的部分。K 这之前匹配的都废弃,所以这之后的将由于-o打印)
或者,如果无法使用grep -P,可以使用同样效果的Perl:

$ perl -lne 'if (/server_name ([^ ;]+)/) {print $1; exit 0}' getyou

或者GNU sed:

$ sed -ne '/server_name/{s/.*server_name //; s/[; ].*//; p; q}' getyou

使用Python简单模拟Linux系统的tree工具

Linux系统中有个tree工具可以用比较好看的形式来显示指定文件夹的目录结构。例如下图(来自于网络):

未分类

本文代码使用Python对Linux系统的tree命令简单进行了模拟,不过还不是特别像,大家可以在此基础上进行改写或者扩展。

import os
import os.path


def tree(path, depth=0):
    if depth == 0:
        print(path)
    items = os.listdir(path)
    for item in items:
        # 输出文件夹中的文件和子文件夹名
        print('|    '*depth, end='')
        print('|----', item)
        item = os.path.join(path, item)
        if os.path.isdir(item):
            # 递归遍历子目录
            tree(item, depth+1)


tree(r'g:test')

运行结果:

未分类

Linux运维工程师应该知道的20条Linux 命令

未分类

在这个全新的工具和多样化的开发环境井喷的大环境下,任何开发者和工程师都有必要学习一些基本的系统管理命令。特定的命令和工具包可帮助开发者组织、排查故障并优化他们的应用程序,而且当出现错误时,也可以为运维人员和系统管理员提供有价值的分类信息。

无论你是新手开发者还是希望管理自己的应用程序,下面 20 条基本的系统管理命令都可以帮助您更好地了解您的应用程序。它们还可以帮助解决为什么应用程序可在本地正常工作但不能在远程主机上工作这类的系统故障。这些命令适用于 Linux 开发环境、容器和虚拟机。

1. curl

curl 用于传输一个 URL。可以使用这条命令用于测试应用程序的端点或与上游服务端点的连接。curl 还可用于检查你的应用程序是否能连接到其他服务,例如数据库,或检查您的服务是否处于健康的状态。

举个例子,假如你的应用程序抛出一个 HTTP 500 错误,表示无法访问 MongoDB 数据库:

$ curl -I -s myapplication:5000

HTTP/1.0 500 INTERNAL SERVER ERROR

-I 选项用于显示头信息, -s 选项表示使用静默模式,不显示错误和进度。检查数据库的端点是否正确:

$ curl -I -s database:27017

HTTP/1.0 200 OK

那么可能是什么问题呢? 检查您的应用程序是否可以访问数据库以外的其他位置:

$ curl -I -s https://opensource.com

HTTP/1.1 200 OK

看起来这没问题,现在尝试访问数据库。您的应用程序正在使用数据库的主机名,因此请先尝试:

$ curl database:27017

curl: (6) Couldn't resolve host 'database'

这表示您的应用程序无法解析数据库,因为数据库的 URL 不可用或主机(容器或VM)没有可用于解析主机名的域名服务器。

2. python -m json.tool / jq

使用 curl 后,API 调用的输出可读性可能较差。有时候,你希望将生成的 JSON 数据格式化输出以查找特定的条目。Python 有一个内置的库可帮助您实现这个需求。可以使用 python -m json.tool 来缩进和组织 JSON。要使用 Python 的 JSON 模块,需要使用管道机制,将 JSON 文件的输出作为输入,写入到 python -m json.tool 命令行。

$ cat test.json
{"title":"Person","type":"object","properties":{"firstName":{"type":"string"},"lastName":{"type":"string"},"age":{"description":"Age in years","type":"integer","minimum":0}},"required":["firstName","lastName"]}

要使用 Python 库,使用 -m (module) 选项将输出内容和 Python 库组合成管道。

$ cat test.json | python -m json.tool
{
    "properties": {
        "age": {
            "description": "Age in years",
            "minimum": 0,
            "type": "integer"
        },
        "firstName": {
            "type": "string"
        },
        "lastName": {
            "type": "string"
        }
    },
    "required": [
        "firstName",
        "lastName"
    ],
    "title": "Person",
    "type": "object"
}

对于更高级的 JSON 解析,可以安装 jq 。j q 提供了一些从 JSON 输入中提取特定值的选项。要像上面的 Python 模块一样将 JSON 输出格式化,只需将 jq 应用到输出即可。

$ cat test.json | jq
{
  "title": "Person",
  "type": "object",
  "properties": {
    "firstName": {
      "type": "string"
    },
    "lastName": {
      "type": "string"
    },
    "age": {
      "description": "Age in years",
      "type": "integer",
      "minimum": 0
    }
  },
  "required": [
    "firstName",
    "lastName"
  ]
}

3. ls

ls 用于列出目录中的文件,系统管理员和开发者会经常使用这个命令。在容器空间中,这条命令可以帮助确定容器镜像中的目录和文件。除了查找文件, ls 还可以用于检查权限。下面的示例中,由于权限问题,你不能运行 myapp。当你使用 ls -l 检查权限时,你会发现它的权限在 -rw-r–r– 中没有”x”,只有读写的权限。

$ ./myapp
bash: ./myapp: Permission denied
$ ls -l myapp
-rw-r--r--. 1 root root 33 Jul 21 18:36 myapp

4. tail

tail 显示文件的最后一部分内容。通常情况下,你不需要浏览每行日志以进行故障排除。而是需要检查日志中对应用程序的最新请求的说明。例如,当你向 Apache HTTP 服务器发起请求时,可以使用 tail 来检查日志中发生的情况。

未分类

使用 tail -f 来跟踪日志文件并在发起请求时查看它们。

-f选项表示跟随的意思,它可在日志被写入文件时输出它们。下面的示例具有每隔几秒访问端点的后台脚本,日志会记录请求。除了实时跟踪日志,还可以使用 tail 带上 -n 选项来查看文件的最后 100 行。

$ tail -n 100 /var/log/httpd/access_log

5. cat

cat主要用于查看文件内容和合并文件。你可能会使用 cat 来检查依赖项文件的内容,或确认已在本地构建的应用程序的版本。

$ cat requirements.txt
flask
flask_pymongo

上面的示例检查您的 Python Flask 应用程序是否已将 Flask 列为依赖项。

6. grep

grep 能使用特定模式匹配(包括正则表达式)搜索文本。如果你在另一条命令的输出中寻找特定的模式, grep 会高亮显示相关的行。可使用这条命令来搜索日志文件以及特定的进程等。如果想查看 Apache Tomcat 是否启动,你可能会命令行的数量给淹没。但讲输出的内容和 grep 命令组合成管道,可以将表示服务器已启动的行独立出来。

$ cat tomcat.log | grep org.apache.catalina.startup.Catalina.start
01-Jul-2017 18:03:47.542 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in 681 ms

7. ps

ps 用于查看进程的各种状态信息。使用该命令可确定正在运行的应用程序或确认预期的进程。例如,如果要检查正在运行的 Tomcat Web 服务器,可使用带有选项的 ps 来获取 Tomcat 的进程 ID。

$ ps -ef
UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  2 18:55 ?        00:00:02 /docker-java-home/jre/bi
root        59     0  0 18:55 pts/0    00:00:00 /bin/sh
root        75    59  0 18:57 pts/0    00:00:00 ps -ef

为了更好的易读性,可使用 grep 和 ps 组合成管道。

$ ps -ef | grep tomcat
root         1     0  1 18:55 ?        00:00:02 /docker-java-home/jre/bi

8. env

env 用于列出所有环境变量及为其赋值。在故障排除期间,你可能会发现需要检查是否有错误的环境变量来阻止应用程序启动。在下面的示例中,该命令用于检查程序主机上设置的环境变量。

$ env
PYTHON_PIP_VERSION=9.0.1
HOME=/root
DB_NAME=test
PATH=/usr/local/bin:/usr/local/sbin
LANG=C.UTF-8
PYTHON_VERSION=3.4.6
PWD=/
DB_URI=mongodb://database:27017/test

请注意,该应用程序正在使用 Python 3,并具有连接到 MongoDB 数据库的环境变量。

9. top

top 用于显示系统中各个进程的信息和资源占用状况,类似于 Windows 的任务管理器。使用该命令可确定哪些进程正在运行,以及它们消耗了多少的内存和 CPU。一种常见的情况是当你运行一个应用程序时,它在一分钟后挂掉。这时,你首先检查应用程序的返回错误,发现是一个内存错误。

$ tail myapp.log
Traceback (most recent call last):
MemoryError

你的应用是否真的内存不足?要确认这个问题,可使用 top 来查看应用程序消耗多少 CPU 和内存。当使用 top 命令后,您注意到一个 Python 应用程序使用了大部分的 CPU,其内存使用量也迅速攀升。当它运行时,如果进程是你的应用程序,则按”C”键来查看完整命令并进行逆向工程。发现原来是你的内存密集型应用程序( memeater.py )。当你的应用程序已经用尽内存,系统会杀掉它并返回一个内存不足(OOM)的错误。

未分类

应用程序的内存和 CPU 使用量增加,最终因为内存不足而被杀掉。

未分类

通过按下”C”键,可以看到启动该应用程序的完整命令

除了检查应用程序,还可以使用 top 来调试其他使用 CPU 或内存的进程。

10. netstat

netstat 用于显示网络状态信息。该命令可显示正在使用的网络端口及其传入连接。但是, netstat 在 Linux 中不能开箱即用。如果需要安装它,需要在 net-tools 包中找到它。作为在本地进行试验或将应用程序推送到主机的开发者,可能会收到端口已被分配或地址已被使用的错误。使用 netstat 得到协议、进程和端口这些信息,下图表明 Apache HTTP 服务器已经在下面的主机上使用了 80 端口。

未分类

使用 netstat -tulpn 表明 Apache 已经在这台机器上使用了 80 端口。

11. ip address

如果 ip address 在你的主机上不能使用,必须使用 iproute2 包进行安装。 i p address 用于显示应用程序的主机接口和 IP 地址。可使用 i p address 来验证你的容器或主机的 IP 地址。例如,当你的容器连接到两个网络时, i p address 可显示哪个接口连接到了哪个网络。对于简单的检查,可以随时使用 ip address 命令获取主机的 IP 地址。下面的示例展示了在接口 eth0 上的 Web 层容器的 IP 地址为 172.17.0.2

未分类

使用 ip address 显示 eth0 接口的 IP 地址为 172.17.0.2

12. lsof

lsof用于列出当前系统打开的文件(list open files)。在某些 Linux 系统中,可能需要使用 lsof 包来安装 lsof 。在 Linux 中,几乎任何和系统的交互都被视为一个文件。因此,如果你的应用程序写入文件或代开网络连接, lsof 将会把这个交互映射为一个文件。与 netstat 类似,可使用 lsof 来检查侦听端口。例如,如果要检查 80 端口是否正在被使用,可使用 lsof 来检查哪个进程正在使用它。下面的示例中,可以看到 httpd (Apache) 在 80 端口上侦听。还可以使用 lsof 来检查 httpd 的进程ID,检查 Web 服务器的二进制文件所在位置( /usr/sbin/httpd )。

未分类

Lsof 表明了 httpd 在 80 端口上侦听。检查 httpd 的进程ID还可以显示所有需要运行的文件httpd。

打开文件列表中的打开文件的名称有助于确定进程的来源,特别是 Apache。

13. df

可以使用 df 显示空闲的磁盘空间(display free disk space)以排查磁盘空间问题。挡在容器管理器上运行应用程序时,可能会收到一条错误信息,提示容器主机上缺少可用空间。虽然磁盘空间应该由系统管理程序来管理和优化,你仍可以使用 df 找出目录中的现有空间并确认是否没有空间。

未分类

Df显示每个文件系统的磁盘空间、绝对空间以及其可用性。

-h 选项表示以可读性较高的方式来显示信息,上面的例子表示这个主机具有大量的磁盘空间。

14. du

du命令也是用于查看使用空间的,但是与 df 命令不同的是 du 命令是对文件和目录磁盘使用的空间的查看,要获取有关哪些文件在目录中使用磁盘空间的更多详细信息,可以使用 du 命令,和 df 命令还是有一些区别的。例如,你想了解那个日志文件占用 /var/log 目录最多的空间,可以使用 du 命令加上 -h 选项和用于获取总大小的 -s 选项。

$ du -sh /var/log/*
1.8M  /var/log/anaconda
384K  /var/log/audit
4.0K  /var/log/boot.log
0 /var/log/chrony
4.0K  /var/log/cron
4.0K  /var/log/maillog
64K /var/log/messages

上面的示例中显示了 /var/log 下的的最大目录为 /var/log/audit 。可以将 du 和 df 搭配使用,以确定在应用程序的主机上使用的磁盘空间。

15. id

要检查运行应用程序的用户,可使用 id 命令来返回用户身份。 id 命令可以显示真实有效的用户ID(UID)和组ID(GID)。下面的示例使用 Vagrant 来测试应用程序并隔离其开发环境。登录进 Vagrant 盒子后,如果尝试安装 Apache HTTP Server(依赖关系),系统会提示你需要以 root 身份执行该命令。要检查你的用户ID和组ID,使用 id 命令,会发现你正在”vagrant”组中以”vagrant”用户身份运行。

$ yum -y install httpd
Loaded plugins: fastestmirror
You need to be root to perform this command.
$ id
uid=1000(vagrant) gid=1000(vagrant) groups=1000(vagrant) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023

要解决此问题,必须以超级用户的身份运行该命令,这将提供提升的权限。

16. chmod

c hmod 命令用来变更文件或目录的权限。当你在主机上首次运行应用程序的二进制文件时,可能会收到错误提示信息“拒绝访问”。如 ls 的示例所示,可以用于检查应用程序二进制文件的权限。

$ ls -l
total 4
-rw-rw-r--. 1 vagrant vagrant 34 Jul 11 02:17 test.sh

这表明您没有权限(没有“x”)来运行二进制文件。 c hmod 可以修改权限,使的用户能够运行二进制文件。

$ chmod +x test.sh
[vagrant@localhost ~]$ ls -l
total 4
-rwxrwxr-x. 1 vagrant vagrant 34 Jul 11 02:17 test.sh

如例子所示,这将更新权限,使其具有可执行的权限。现在当你尝试执行二进制文件时,应用程序不会抛出拒绝访问的错误。当将二进制文件加载到容器时, Chmod 可能很有用。它能保证容器具有合适的权限以执行二进制文件。

17. dig / nslookup

dig 命令是常用的域名查询工具,可以用来测试域名系统工作是否正常。域名服务器(DNS)有助于将 URL 解析为一组应用程序服务器。然而,你会发现有些 URL 不能被解析,这会导致应用程序的连接问题。例如,假如你尝试从应用程序的主机访问你的数据库。你收到一个”不能解析”的错误。要进行故障排查,你尝试使用 dig (DNS 查询工具)或 nslookup (查询 Internet 域名服务器)来确定应用程序似乎无法解析数据的原因。

$ nslookup mydatabase
Server:   10.0.2.3
Address:  10.0.2.3#53

** server can't find mydatabase: NXDOMAIN

使用 nslookup 显示无法解析 mydatabase 。尝试使用 dig 解决,但仍是相同的结果。

$ dig mydatabase

; <<>> DiG 9.9.4-RedHat-9.9.4-50.el7_3.1 <<>> mydatabase
;; global options: +cmd
;; connection timed out; no servers could be reached

这些错误可能是由许多不同的问题引起的。如果无法调试出根本原因,与系统管理员联系以进行更多的调查。对于本地测试,这些问题可能表示你的主机的域名服务器未正确配置。要使用这些命令,需要安装 BIND Utilities 包 。

18. iptables

iptables 用于阻止或允许 Linux 主机上的流量,用于 IP 包过滤器管理,类似于网络防火墙。此工具可阻止某些应用程序接收或发送请求。更具体地说,如果您的应用程序难以访问另一个端点,可能已被 iptables 拒绝流量访问该端点。例如,假设您的应用程序的主机无法访问 Opensource.com,您使用 curl 来测试连接。

$ curl -vvv opensource.com
* About to connect() to opensource.com port 80 (#0)
*   Trying 54.204.39.132...
* Connection timed out
* Failed connect to opensource.com:80; Connection timed out
* Closing connection 0
curl: (7) Failed connect to opensource.com:80; Connection timed out

连接超时。您怀疑某些东西可能会阻塞流量,因此您使用 -S 选项显示 iptables 规则。

$ iptables -S
-P INPUT DROP
-P FORWARD DROP
-P OUTPUT DROP
-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -i eth0 -p udp -m udp --sport 53 -j ACCEPT
-A OUTPUT -p tcp -m tcp --sport 22 -j ACCEPT
-A OUTPUT -o eth0 -p udp -m udp --dport 53 -j ACCEPT

前三个规则显示,默认情况下流量已被丢弃。剩下的规则表示允许 SSH 和 DNS 流量。在这种情况下,如果需要允许流量到外部端点的规则,请跟上 sysadmin。如果这是用于本地开发或测试的主机,可使用 iptables 命令来允许合适的流量。添加允许到主机的流量的规则时一定要谨慎。

19. sestatus

通常会在企业管理的应用程序主机上使用 SELinux(一个 Linux 安全模块)。SELinux 对主机上运行的进程提供最低权限的访问,防止潜在的恶意进程访问系统上的重要文件。某些情况下,应用程序需要访问特定文件,但可能会发生错误。要检查 SELinux 是否阻止了应用程序,使用 tail 和 grep 在 /var/log/audit 日志记录中查找”denied”(被拒绝)的信息。否则,使用 sestatus 来检查是否启动了 SELinux。

$ sestatus
SELinux status:                 enabled
SELinuxfs mount:                /sys/fs/selinux
SELinux root directory:         /etc/selinux
Loaded policy name:             targeted
Current mode:                   enforcing
Mode from config file:          enforcing
Policy MLS status:              enabled
Policy deny_unknown status:     allowed
Max kernel policy version:      28

上面的输出表示应用程序的主机已启用 SELinux。在本地开发环境中,可以更新 SELinux 使得权限更宽松。

20. history

当你使用大量的命令进行测试和调试时,可能会忘记有用的命令。每个 shell 都有一个 history 命令的变体。它可显示自会话开始以来使用的命令的历史记录。可以使用 history 来记录用来排除应用程序故障的命令。history 命令用于显示指定数目的指令命令,读取历史命令文件中的目录到历史命令缓冲区和将历史命令缓冲区中的目录写入命令文件。

$ history
    1  clear
    2  df -h
    3  du

如果希望执行之前历史记录中的命令,但又不想重新输入,该怎么办?使用符号 ! 即可,可以使用符号 ! 执行指定序号的历史命令。例如,要执行第 2 个历史命令,则输入!2,

未分类

在需要重新执行的命令的指定编号前添加 ! 即可重新执行

这些基本命令能增强排查故障的专业技能,可检查为什么应用程序可以在一个开发环境中工作,而在另一个开发环境中则不可以。许多系统管理员使用这些命令来调试系统问题。了解一些有用的故障排查命令可帮助解决应用程序的问题。