轉載於:https://zhangge.net/5093.html
朋友弄了一個小項目,要我幫忙做下 Linux 系統運維,上線一段時間后,發現項目偶爾會掛掉導致服務不可用。開發朋友一時之間也沒空去研究項目奔潰的根因,只好由我這個運維先寫一個項目進程自拉起腳本,通過 Linux 任務計划每分鍾檢查一下進程是否存在來避免項目掛了沒人管的情況。
自拉起腳本很簡單,隨便寫幾行就搞定了:
1
2
3
4
5
6
7
8
9
10
|
#!/bin/bash
processcount=$(pgrep my_app|wc -l)
cd $(cd $(dirname $0) && pwd)
if [[ 0 -eq $processcount ]]
then
echo "[ $(date) ] : my_app is down, start it!" | tee -ai ./checkprocess.log
bash ./start.sh #這里是項目的重啟腳本
else
echo my_app is OK!
fi
|
然后丟到 crontab,1 分鍾執行一次:
1
|
* * * * * bash /data/app_server/checkprocess.sh >/dev/null 2>&1
|
本以為萬事大吉了,結果還是坑了,進程再一次掛了,尼瑪什么鬼?
一、檢查日志
根據經驗,先看一下 crontab 的日志:
tail /var/log/messages
沒發現相關日志,看來不是打印到了這,於是查看了下 crontab 的默認日志位置:
tail /var/log/cron
1
2
3
4
|
Mar 25 21:40:01 li733-135 CROND[1959]: (root) CMD (sh /data/app_server/checkprocess.sh >/dev/null 2>&1)
Mar 25 21:40:01 li733-135 CROND[1960]: (root) CMD (/usr/lib64/sa/sa1 1 1)
Mar 25 21:40:01 li733-135 CROND[1961]: (root) CMD (/usr/sbin/ntpdate pool.ntp.org > /dev/null 2>&1)
Mar 25 21:41:01 li733-135 CROND[2066]: (root) CMD (sh /data/app_server/checkprocess.sh >/dev/null 2>&1)
|
很明顯,任務計划確實在正常執行着,看來問題在腳本上了。
二、檢查腳本
①、直接執行
檢查腳本第一步,直接按照 crontab 里面的命令行,執行腳本:
1
2
3
4
5
|
sh /data/app_server/checkprocess.sh
[ Fri Mar 25 21:25:01 CST 2016 ] : my_app is down, start it!
sh /data/app_server/checkprocess.sh
my_app is OK!
|
結果進程正常拉起了!
直接執行成功,而放到 crontab 就失敗,經驗告訴我肯定的腳本環境變量有問題了!
②、環境變量
於是在腳本里面載入環境變量:
1
2
3
4
|
#!/bin/bash
#先載入環境變量
source /etc/profile
#其他代碼不變
|
然后手工把進程殺死,等待自拉起,結果... 還是不行!
③、系統郵件
經驗告訴我,crontab 執行失敗,如果沒有屏蔽錯誤的話,會產生一個系統郵件,
位置在 /var/spool/mail/root
所以,我把 crontab 里面的 2>&1 這個屏蔽錯誤先取消掉,等待幾分鍾查看郵件。
cat /var/spool/mail/root 發現有如下報錯:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
From root@free-node-us.localdomain Fri Mar 25 21:30:02 2016
Return-Path: <root@app_server.localdomain>
X-Original-To: root
Delivered-To: root@app_server.localdomain
Received: by app_server.localdomain (Postfix, from userid 0)
id 78DB5403E2; Fri, 25 Mar 2016 21:19:02 +0800 (CST)
From: root@app_server.localdomain (Cron Daemon)
To: root@app_server.localdomain
Subject: Cron <root@app_server> bash /data/app_server/checkprocess.sh >/dev/null
Content-Type: text/plain; charset=UTF-8
Auto-Submitted: auto-generated
X-Cron-Env: <LANG=en_US.UTF-8>
X-Cron-Env: <SHELL=/bin/sh>
X-Cron-Env: <HOME=/root>
X-Cron-Env: <PATH=/usr/bin:/bin>
X-Cron-Env: <LOGNAME=root>
X-Cron-Env: <USER=root>
Message-Id: <20160325131902.78DB5403E2@app_server.localdomain>
Date: Fri, 25 Mar 2016 21:19:02 +0800 (CST)
start.sh: line 4: /sbin/sudo: No such file or directory #sudo命令找不到!我次奧·~
|
居然是腳本里面的 sudo 執行失敗了,找不到這個文件。看來單純的載入 profile 不一定靠譜啊!
③、修復腳本
知道問題所在,解決就簡單了,粗暴點,直接寫入 sudo 的絕對路徑 /usr/bin/sudo
繼續測試自拉起,結果... 還是不行!R 了 G 了!!
三、最終解決
繼續查看了下系統郵件,發現如下信息:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
Subject: Cron <root@free-node-us> source /etc/profile;bash /data/app_server/checkprocess.sh >/dev/null
Content-Type: text/plain; charset=UTF-8
Auto-Submitted: auto-generated
X-Cron-Env: <LANG=en_US.UTF-8>
X-Cron-Env: <SHELL=/bin/sh>
X-Cron-Env: <HOME=/root>
X-Cron-Env: <PATH=/usr/bin:/bin>
X-Cron-Env: <LOGNAME=root>
X-Cron-Env: <USER=root>
Message-Id: <20160325132403.0E8E1403E2@app_server.localdomain>
Date: Fri, 25 Mar 2016 21:24:03 +0800 (CST)
sudo: sorry, you must have a tty to run sudo #原來是這個問題!
|
很明顯,提示了 sudo 必須需要 tty 才能執行,解決很簡單,取消這個限制即可!
編輯 /etc/sudoers ,找到 Defaults requiretty, 然后注釋掉這行:
1
2
3
|
vim /etc/sudoers
#Defaults requiretty
|
最后使用 :x! 或 :wq! 強制保存即可。
結果觀察還是報了相同的錯誤!原來改完這個 sudo 並不會影響已經運行的 crontab,所以需要重啟 crontab 服務刷新下設置:
1
|
service crond restart
|
這下終於可以了!
四、分析總結
Linux 系統里面計划任務,crontab 沒有如期執行這是運維工作中比較常見的一種故障了,根據經驗,大家可以從如下角度分析解決:
①、檢查 crontab 服務是否正常
這個一般通過查看日志來檢查,也就是前文提到的 /var/log/cron 或 /var/log/messages,如果里面沒有發現執行記錄,那么可以重啟下這個服務:service crond restart
②、檢查腳本的執行權限
一般來說,在 crontab 中建議使用 sh 或 bash 來執行 shell 腳本,避免因腳本文件的執行權限丟失導致任務失敗。當然,最直接檢查就是人工直接復制 crontab -l 里面的命令行測試結果。
③、檢查腳本需要用到的變量
和上文一樣,通常來說從 crontab 里面執行的腳本和人工執行的環境變量是不一樣的,所以對於一些系統變量,建議寫絕對路徑,或使用 witch 動態獲取,比如 sudo_bin=$(which sudo) 就能拿到 sudo 在當前系統的絕對路徑了。
④、放大招:查看日志
其實,最直接最有效的就是查看執行日志了,結合 crontab 執行記錄,以及 crontab 執行出錯后的系統郵件,一般都能徹底找到失敗的原因了!當然,要記住在 crontab 中如果屏蔽了錯誤信息,就不會發郵件了。
這又讓我想起了如果 crontab 未屏蔽日志,可能會導致硬盤 inode 爆滿 ==> 歷史文章傳送門 ,感興趣的童鞋也可以谷歌一下 /var/spool/clientmqueue/ 這個關鍵詞了解下。
好了,本文分享到此,希望對你有所幫助!
Centos7已經寫了要chmod +x /etc/rc.d/rc.local 授權一下才會起作用
當然有的時候也可能不成功,比如:
/etc/rc.d/rc.local 文件中的內容格式不正確:
開頭少了#!/bin/bash,也是執行不成功的,會提示你格式不對。
也可能由於是環境變量的問題
可直接在/etc/rc.local文件中加入:source /etc/profile
或者 通過 su -c
自動帶入環境變量
此外還可能是沒有啟動此項服務:
#systemctl list-units --type=service #來查看一下所有的開啟啟動項目里面有沒有這個rc-local這個服務。
#systemctl status rc-local.service #來查看一下當前是怎么個狀態
然后:
#systemctl enable rc-local.service
#systemctl start rc-local.service
#手工添加下開機啟動或者手工起一下看報錯信息。
另外:服務的啟動文件是存放在了:/lib/systemd/system/目錄下面,如果不記得這個服務的全稱可以來這個目錄下面看。