当网络三个小时不使用时,如何让 Ubuntu 服务器休眠?

当网络三个小时不使用时,如何让 Ubuntu 服务器休眠?

我实际上每周只使用几天,每天使用服务器几个小时。

它是一个备份服务器,它向客户端请求备份数据。

这部分已经处理好了,它通过预定的魔术包唤醒并执行其任务。一切都很好。我可以唤醒它以在计划外使用它,这也很好。

我如何让它知道网络已经有一段时间没有使用了,并让它进入睡眠状态?我想要记录的网络流量是 SSH、SFTP、rsync 和来自 Canonical 的更新。所有其他流量都是我不关心的闲聊。

我可能想将以下伪代码放入 cron 脚本中...每 15 分钟左右检查一次。我并不担心添加 cron 功能,我对此很有信心。

if [ lastSignificantNetworkActivity > 3h ] { hibernate }

我可能遇到了 X->Y 问题。我只想将我的服务器置于低功耗磁盘保存状态,通常 18 小时它不会执行任何操作。我认为网络活动是一个很好的测试指标。我愿意接受更完善、更强大的解决方案或固有的服务器属性来检查是否存在。

(我不确定每天的电源循环是否会比 ZFS 整天运行数据完整性检查而造成的持续磨损更糟糕……只是不确定。)

答案1

一种可能的实现方法是通过防火墙规则来找出 SSH 会话生成的网络流量的迹象:

  • 最初,在启动时加载与往返于 22/tcp 端口的流量匹配的规则;
  • 然后,脚本定期从防火墙检索统计信息,并将这些规则的命中次数存储到临时文件中;
  • 该脚本将能够通过检测任何命中数的变化来检测网络流量。

由于这两个应用程序都通过 SSH 协议运行,因此该方法还可以检测 SFTP 和 RSYNC 生成的流量。

通过防火墙检测更新活动会比较困难,因为软件包下载使用 FTP、HTTP 和 HTTPS 协议,需要调整防火墙规则以区分软件更新和记录的 HTTP 流量。因此,我的建议是通过检查 、 和 的修改时间来检测/var/lib/apt/lists软件/var/cache/apt/archives更新/var/lib/dpkg/lock

我的实施方案如下:


这些命令行设置iptablesip6tables规则。

# apt-get install iptables-persistent

# iptables -w -N fwstats
# iptables -w -A fwstats
# iptables -w -A INPUT -p tcp --dport 22 -m state --state ESTABLISHED -j fwstats
# iptables -w -A OUTPUT -p tcp --dport 22 -m state --state ESTABLISHED -j fwstats
# iptables-save > /etc/iptables/rules.v4

# ip6tables -w -N fwstats
# ip6tables -w -A fwstats
# ip6tables -w -A INPUT -p tcp --dport 22 -m state --state ESTABLISHED -j fwstats
# ip6tables -w -A OUTPUT -p tcp --dport 22 -m state --state ESTABLISHED -j fwstats
# ip6tables-save > /etc/iptables/rules.v6

这是等效的设置nftables

# apt-get install nftables
# nft add chain inet filter fwstats
# nft add rule inet filter fwstats counter
# nft add rule inet filter input tcp dport ssh ct state established jump fwstats
# nft add rule inet filter output tcp dport ssh ct state established jump fwstats
# echo -e \#\!`which nft` -f\\nflush ruleset > /etc/nftables.conf
# nft list ruleset >> /etc/nftables.conf

这是一个监控脚本的模板,具体getStats功能需要根据使用的防火墙进行调整。

#!/bin/bash

getStats () {
    if using_nftables; then
        nft list chain inet filter fwstats | grep counter
    elif using_xtables; then
        for xtable in iptables ip6tables; do
            "${xtable}" -w -xnvL fwstats | egrep '^([[:space:]]+[0-9]+){2,2}'
        done
    fi
}

stateFile="/run/hibernation_state"

currentStats="`getStats`"
if [ "x${currentStats}" != "x" ]; then
    previousStats="`cat \"${stateFile}\"`"
    if [ "x${currentStats}" == "x${previousStats}" ]; then
        # No network traffic has been detected. Check files related do DPKG and APT
        clearToHibernate='true'
        now="`date '+%s'`"
        for path in "${stateFile}" \
            '/var/lib/apt/lists' \
            '/var/cache/apt/archives' \
            '/var/lib/dpkg/lock' ; do
            pathModTime="`stat -c '%Y' "${path}"`"
            # 10800 seconds = 3 hours
            if [ "$((now-10800))" -lt "${pathModTime}" ]; then
                clearToHibernate='false'
            fi
        done
        if "${clearToHibernate}"; then
            # OK to hibernate.
            systemctl hibernate
        fi
    else
        # Network traffic has been detected. Refresh stats.
        echo "${currentStats}" > "${stateFile}"
    fi
fi

答案2

这个想法太糟糕了!让我们自己想办法吧!

使忽略的 SSH 会话过期

cat > /etc/ssh/sshd_config <<EOF
AcceptEnv LANG LC_*
Banner none
ChallengeResponseAuthentication no
ClientAliveCountMax 0
ClientAliveInterval 1800
PasswordAuthentication yes
PrintMotd no
Subsystem sftp /usr/lib/openssh/sftp-server
UsePAM yes
X11Forwarding yes
EOF

安装 Hibernate

apt install hibernate

设置系统范围的日志格式,为了好玩

echo "HISTTIMEFORMAT=\"%Y-%m-%d %T \"" > /etc/environment

启动一个 cron 任务!

echo "0,12,24,36,48  *    * * *   root    bash /usr/local/sbin/hibernation" >> /etc/crontab

现在,情况变得糟糕透了:

cat <<-EOF > /usr/local/sbin/hibernation

#!/bin/bash -i

# The hibernation delay script

echo "----------------------" >> /tmp/justchecking.txt

EXTEND=0
SCRIPTTIME=$(date +%s)

echo $(date) >> /tmp/justchecking.txt

echo "script timetamp" $SCRIPTTIME >> /tmp/justchecking.txt

# Make sure there is a hibernation time file

if [ ! -f /var/run/hibernation.time.txt ]
    then
        echo $SCRIPTTIME > /var/run/hibernation.time.txt
        echo "created hibernation.time.txt sbin script" >> /tmp/justchecking.txt
fi

SLEEPTIME=$(</var/run/hibernation.time.txt)

if [ $SLEEPTIME -eq 999999999999 ]
    then
        echo "just came out of suspend, set extend to 360" >> /tmp/justchecking.txt
        EXTEND=360
fi

# Check the logs for recent activity

HISTTIMEFORMAT="%Y-%m-%d %T "
HISTFILE=/root/.bash_history
set -o history
history 75 > /tmp/recenthistory.txt
set +o history
unset HISTFILE
ece
echo $(tail -n5 /var/log/apt/history.log | head -n1) "apt" >> /tmp/recenthistory.txt
LASTACTIVITY=$(grep -e apt -e dpkg -e chebackup /tmp/recenthistory.txt | tail -n1 | awk '{print $2" "$3}')
echo "last activity" $LASTACTIVITY >> /tmp/justchecking.txt

#LASTACTIVITYDATE="$(</tmp/recenthistory.txt)"

#echo "last activity date"$LASTACTIVITYDATE"." >> /tmp/justchecking.txt

# Store last activity date time as a timestamp

ACTIVITYTIMESTAMP=$(date -d "$LASTACTIVITY" +%s)
echo "activity time stamp" $ACTIVITYTIMESTAMP >> /tmp/justchecking.txt

# Calculate 

ACTIVITYCOOLDOWNTIME=$(( 3960 - ( $SCRIPTTIME - $ACTIVITYTIMESTAMP ) ))

echo "activity cool down time" $ACTIVITYCOOLDOWNTIME >> /tmp/justchecking.txt

(($ACTIVITYCOOLDOWNTIME > 0)) && EXTEND=$ACTIVITYCOOLDOWNTIME
echo "extend variable after activity cool down command" $EXTEND >> /tmp/justchecking.txt

#if [ $ACTIVITYCOOLDOWNTIME > 0 ]
#    then
#        echo "activity was recent, adding cooldowntime to extend" >> /tmp/justchecking.txt
#        EXTEND = $ACTIVITYCOOLDOWNTIME
#fi

# Check for updates or backup currently running

if [ $(ps -aux | grep -e apt -e dpkg -e chebackup | wc -l) -gt 1 ]
    then
        EXTEND=3960
        SLEEPTIME=$(($SCRIPTTIME + $EXTEND))
        echo $(ps -aux | grep -e apt -e dpkg -e chebackup | wc -l) > /tmp/justchecking.txt
        echo "activity actively running, extended 3960" >> /tmp/justchecking.txt
fi

# Check for any users logged in

if [ $(who -u | wc -l) -gt 0 ]
    then
        EXTEND=10800
        #EXTEND=180
        echo $(who -u) >> /tmp/justchecking.txt
        echo "extended 10800" >> /tmp/justchecking.txt
        #echo "extend 180" >> /tmp/justchecking.txt
fi

echo "sleeptime" $SLEEPTIME >> /tmp/justchecking.txt

if [ $EXTEND -gt 0 ]
    then
        SLEEPTIME=$(($SCRIPTTIME + $EXTEND))
fi

if [ $SLEEPTIME -lt $SCRIPTTIME ]
    then
        echo "hibernate" >> /tmp/justchecking.txt
        echo $(date +%s) >> /tmp/justchecking.txt
        echo "hibernate" >> /tmp/justchecking.txt
        echo "999999999999" > /var/run/hibernation.time.txt
        hibernate &
        disown
    else
        echo $SLEEPTIME > /var/run/hibernation.time.txt
        echo "update sleeptime" $SLEEPTIME >> /tmp/justchecking.txt
fi

tail -n100 /tmp/justchecking.txt > /tmp/justchecking.txt
wc -l /tmp/justchecking.txt >> /tmp/justchecking.txt

exit 0

EOF

不要忘记更改权限

chmod 500 /usr/local/sbin/hibernation

相关内容