本文目录导读:

我来详细介绍如何实现服务启停脚本,包含不同场景的实现方式。
Systemd Service (推荐 - Linux系统)
创建服务文件
sudo vi /etc/systemd/system/myapp.service
[Unit] Description=My Application Service After=network.target [Service] Type=simple User=myapp Group=myapp WorkingDirectory=/opt/myapp ExecStart=/usr/bin/python3 /opt/myapp/app.py ExecStop=/bin/kill -SIGTERM $MAINPID ExecReload=/bin/kill -SIGHUP $MAINPID Restart=on-failure RestartSec=5 StandardOutput=journal StandardError=journal [Install] WantedBy=multi-user.target
命令使用
# 启动服务 sudo systemctl start myapp # 停止服务 sudo systemctl stop myapp # 重启服务 sudo systemctl restart myapp # 查看状态 sudo systemctl status myapp # 开机自启 sudo systemctl enable myapp
Shell脚本版 (通用)
基本服务启停脚本
#!/bin/bash
# 配置项
APP_NAME="myapp"
APP_PATH="/opt/myapp"
APP_CMD="python3 app.py"
PID_FILE="/var/run/${APP_NAME}.pid"
LOG_FILE="/var/log/${APP_NAME}.log"
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# 获取进程PID
get_pid() {
if [ -f "${PID_FILE}" ]; then
cat "${PID_FILE}"
else
echo ""
fi
}
# 检查服务状态
status() {
local pid=$(get_pid)
if [ -n "${pid}" ] && kill -0 "${pid}" 2>/dev/null; then
echo -e "${GREEN}${APP_NAME} 正在运行 (PID: ${pid})${NC}"
return 0
else
echo -e "${RED}${APP_NAME} 未运行${NC}"
return 1
fi
}
# 启动服务
start() {
echo -e "${YELLOW}正在启动 ${APP_NAME}...${NC}"
# 检查是否已运行
if status > /dev/null 2>&1; then
echo -e "${YELLOW}${APP_NAME} 已经在运行中${NC}"
return 1
fi
# 进入工作目录
cd "${APP_PATH}" || {
echo -e "${RED}无法进入工作目录: ${APP_PATH}${NC}"
return 1
}
# 启动服务
nohup ${APP_CMD} >> "${LOG_FILE}" 2>&1 &
local pid=$!
echo ${pid} > "${PID_FILE}"
# 等待启动完成
sleep 2
if kill -0 "${pid}" 2>/dev/null; then
echo -e "${GREEN}${APP_NAME} 启动成功 (PID: ${pid})${NC}"
return 0
else
echo -e "${RED}${APP_NAME} 启动失败,请检查日志${NC}"
return 1
fi
}
# 停止服务
stop() {
echo -e "${YELLOW}正在停止 ${APP_NAME}...${NC}"
local pid=$(get_pid)
if [ -z "${pid}" ]; then
echo -e "${YELLOW}${APP_NAME} 未在运行${NC}"
return 0
fi
# 先尝试优雅停止
kill "${pid}" 2>/dev/null
# 等待进程结束
local timeout=30
while [ ${timeout} -gt 0 ]; do
if ! kill -0 "${pid}" 2>/dev/null; then
break
fi
sleep 1
timeout=$((timeout - 1))
done
# 如果无法优雅停止,强制终止
if kill -0 "${pid}" 2>/dev/null; then
echo -e "${YELLOW}强制停止进程...${NC}"
kill -9 "${pid}" 2>/dev/null
fi
# 清理PID文件
rm -f "${PID_FILE}"
echo -e "${GREEN}${APP_NAME} 已停止${NC}"
}
# 重启服务
restart() {
stop
sleep 2
start
}
# 查看日志
logs() {
if [ -f "${LOG_FILE}" ]; then
tail -f "${LOG_FILE}"
else
echo -e "${RED}日志文件不存在: ${LOG_FILE}${NC}"
fi
}
# 主函数
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
restart
;;
status)
status
;;
logs)
logs
;;
*)
echo "用法: $0 {start|stop|restart|status|logs}"
exit 1
;;
esac
exit $?
Java应用服务脚本
#!/bin/bash
# Java应用配置
APP_NAME="spring-boot-app"
JAR_NAME="app.jar"
JAVA_HOME="/usr/local/java/jdk11"
APP_DIR="/opt/${APP_NAME}"
JAVA_OPTS="-Xms512m -Xmx1024m -Dspring.profiles.active=prod"
PID_FILE="/var/run/${APP_NAME}.pid"
LOG_FILE="/var/log/${APP_NAME}/app.log"
# 加载环境变量
if [ -f "${APP_DIR}/env.sh" ]; then
source "${APP_DIR}/env.sh"
fi
# 启动Java应用
start() {
echo "Starting ${APP_NAME}..."
cd "${APP_DIR}"
# 使用exec启动Java进程
exec ${JAVA_HOME}/bin/java ${JAVA_OPTS} \
-jar ${APP_DIR}/${JAR_NAME} \
2>&1 &
echo $! > ${PID_FILE}
echo "${APP_NAME} started with PID $(cat ${PID_FILE})"
}
# 优雅停止Java应用
stop() {
echo "Stopping ${APP_NAME}..."
if [ ! -f ${PID_FILE} ]; then
echo "${APP_NAME} is not running"
return 0
fi
local pid=$(cat ${PID_FILE})
# 发送SIGTERM信号
kill -15 ${pid}
# 等待进程结束
for i in $(seq 1 30); do
if ! kill -0 ${pid} 2>/dev/null; then
echo "${APP_NAME} stopped successfully"
rm -f ${PID_FILE}
return 0
fi
sleep 1
done
# 超时后强制停止
echo "Force stopping ${APP_NAME}..."
kill -9 ${pid} 2>/dev/null
rm -f ${PID_FILE}
}
Docker版服务管理
#!/bin/bash
# Docker容器管理
CONTAINER_NAME="myapp"
IMAGE_NAME="myapp:latest"
NETWORK="myapp-network"
VOLUMES="-v /data/myapp:/app/data"
start() {
echo "Starting container ${CONTAINER_NAME}..."
# 检查容器是否存在
if docker ps -a --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then
# 如果存在则启动
docker start ${CONTAINER_NAME}
else
# 不存在则创建并启动
docker run -d \
--name ${CONTAINER_NAME} \
--restart unless-stopped \
--network ${NETWORK} \
${VOLUMES} \
-p 8080:8080 \
${IMAGE_NAME}
fi
}
stop() {
echo "Stopping container ${CONTAINER_NAME}..."
docker stop -t 30 ${CONTAINER_NAME}
}
restart() {
stop
sleep 5
start
}
status() {
docker ps --filter "name=${CONTAINER_NAME}" --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
}
logs() {
docker logs -f --tail 100 ${CONTAINER_NAME}
}
Python装饰器版服务框架
#!/usr/bin/env python3
import os
import sys
import signal
import argparse
import logging
import time
from contextlib import contextmanager
class ServiceManager:
"""服务管理器装饰器"""
def __init__(self, name, pid_file=None, log_file=None):
self.name = name
self.pid_file = pid_file or f"/var/run/{name}.pid"
self.log_file = log_file or f"/var/log/{name}.log"
self.logger = logging.getLogger(name)
self._setup_logging()
def _setup_logging(self):
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler(self.log_file),
logging.StreamHandler(sys.stdout)
]
)
def __call__(self, func):
def wrapper(*args, **kwargs):
parser = argparse.ArgumentParser(description=f'{self.name} Service Manager')
parser.add_argument('action', choices=['start', 'stop', 'restart', 'status'],
help='Service action')
args = parser.parse_args()
if args.action == 'start':
return self._start(func, *args, **kwargs)
elif args.action == 'stop':
return self._stop()
elif args.action == 'restart':
return self._stop() or self._start(func, *args, **kwargs)
elif args.action == 'status':
return self._status()
return wrapper
def _start(self, func, *args, **kwargs):
if self._get_pid() and os.path.exists(f'/proc/{self._get_pid()}'):
self.logger.warning(f"{self.name} is already running")
return
pid = os.fork()
if pid > 0:
# Parent process
with open(self.pid_file, 'w') as f:
f.write(str(pid))
self.logger.info(f"{self.name} started (PID: {pid})")
sys.exit(0)
elif pid == 0:
# Child process
self._daemonize()
func(*args, **kwargs)
def _stop(self):
pid = self._get_pid()
if not pid:
self.logger.info(f"{self.name} is not running")
return
try:
os.kill(pid, signal.SIGTERM)
# Wait for process to exit
for _ in range(30):
time.sleep(1)
if not os.path.exists(f'/proc/{pid}'):
break
else:
os.kill(pid, signal.SIGKILL)
os.remove(self.pid_file)
self.logger.info(f"{self.name} stopped")
except ProcessLookupError:
os.remove(self.pid_file)
self.logger.info(f"{self.name} was not running")
def _status(self):
pid = self._get_pid()
if pid and os.path.exists(f'/proc/{pid}'):
self.logger.info(f"{self.name} is running (PID: {pid})")
return True
else:
self.logger.info(f"{self.name} is not running")
return False
def _get_pid(self):
if os.path.exists(self.pid_file):
with open(self.pid_file) as f:
return int(f.read().strip())
return None
def _daemonize(self):
os.setsid()
os.umask(0)
sys.stdin.close()
sys.stdout.close()
sys.stderr.close()
# 使用示例
@ServiceManager("myapp", pid_file="/tmp/myapp.pid", log_file="/tmp/myapp.log")
def main():
"""Your application main function"""
import time
while True:
print("Service is running...")
time.sleep(10)
if __name__ == "__main__":
main()
最佳实践建议
安全性考虑
# 1. 权限控制
chmod 750 /etc/init.d/myservice
chown root:root /etc/init.d/myservice
# 2. 防止重复启动
if [ -f $PID_FILE ] && kill -0 $(cat $PID_FILE) 2>/dev/null; then
echo "Service is already running"
exit 1
fi
# 3. 资源限制
ulimit -n 65535
ulimit -u 10240
测试脚本
#!/bin/bash
# test_service.sh - 服务脚本测试
# 测试用例
test_service() {
local script=$1
echo "Testing $script..."
# 测试启动
$script start
if [ $? -eq 0 ]; then
echo "✓ Start successful"
else
echo "✗ Start failed"
return 1
fi
# 测试状态
$script status
if [ $? -eq 0 ]; then
echo "✓ Status check passed"
fi
# 测试重启
$script restart
if [ $? -eq 0 ]; then
echo "✓ Restart successful"
fi
# 测试停止
$script stop
if [ $? -eq 0 ]; then
echo "✓ Stop successful"
fi
}
# 运行测试
test_service "./myservice.sh"
选择哪种方式取决于你的具体需求:
- 现代Linux系统:优先使用systemd
- 传统系统或简单服务:使用Shell脚本
- Java应用:使用专门的Java脚本
- 容器化部署:使用Docker管理
- Python应用:使用装饰器框架
建议始终包含错误处理、日志记录和状态检查功能。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播