SSL证书验证

1
2
3
4
5
6
apt install -y openssl

openssl x509 -noout -modulus -in nginx.baby.pem | openssl md5
-------------------------------- 你的公钥证书(certificate)------
openssl rsa -noout -modulus -in nginx.baby.key | openssl md5
-------------------------------- 你的私钥(private key)----------

MD5(stdin)= e3b0c44298fc1c149afbf4c8996fb924
MD5(stdin)= e3b0c44298fc1c149afbf4c8996fb924 <– 一样,说明匹配

若不一致,说明你的 key 与 pem 不匹配,Harbor 启动时会报错 SSL routines:SSL_CTX_use_PrivateKey_file: key values mismatch。

自签证书

1
2
mkdir -p /data/cert
openssl req -newkey rsa:4096 -nodes -sha256 -keyout /data/cert/harbor.key -x509 -days 365 -out /data/cert/harbor.crt

制作docker镜像

docker 镜像

Dockerfile

1
2
3
4
5
6
FROM nginx:latest

COPY nginx.conf /etc/nginx/nginx.conf
COPY htpasswd /etc/nginx/.htpasswd
COPY html/ /usr/share/nginx/html/
COPY ssl/ /etc/nginx/ssl/

制作镜像

1
2
3
4
5
docker build -t mynginx:ssl .
# mynginx:ssl 为镜像名称 . 为当前目录
docker build -t test_nginx_image_backup .
# test_nginx_image_backup 为镜像名称
# . 为当前目录

运行镜像

1
2
3
4
5
6
7
8
docker run -itd \
--name mynginx_ssl \
--restart unless-stopped \
-p 80:80 -p 443:443 \
mynginx:ssl


docker run -itd --name test_nginx --restart unless-stopped test_nginx_image_backup

打成 tar 包

1
2
docker save -o mynginx.tar mynginx:ssl
docker save -o test_nginx_image_backup.tar test_nginx_image_backup

在其他服务器导入镜像

1
2
3
docker load -i mynginx.tar

docker load -i test_nginx_image_backup.tar

远程harbor管理docker

Nginx优化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
user  nginx;
worker_processes auto;

error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;

events {
worker_connections 1024; # 并发连接数限制
use epoll; # Linux 下推荐使用 epoll 模型
multi_accept on; # 尽可能多地接受连接
}

http {
include mime.types;
default_type application/octet-stream;

log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';

access_log /var/log/nginx/access.log main;

sendfile on;
tcp_nopush on;
tcp_nodelay on;

keepalive_timeout 65;
types_hash_max_size 2048;

server_tokens off; # 不暴露 Nginx 版本号,提升安全性

gzip on; # 启用压缩,提升传输效率
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

include /etc/nginx/conf.d/*.conf;

##
## HTTPS Server
##
server {
listen 443 ssl http2; # 开启 HTTP/2
server_name nginx.baby;

ssl_certificate /etc/nginx/ssl/nginx.baby.pem;
ssl_certificate_key /etc/nginx/ssl/nginx.baby.key;

ssl_session_timeout 10m;
ssl_session_cache shared:SSL:10m;
ssl_protocols TLSv1.2 TLSv1.3; # 禁用旧协议
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;

add_header Strict-Transport-Security "max-age=31536000" always; # HSTS 安全强化

location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ =404;
}
}

##
## HTTP Redirect to HTTPS
##
server {
listen 80;
server_name nginx.baby;
return 301 https://$host$request_uri;
}
}
  1. 性能优化

    worker_processes auto:自动根据 CPU 核心数设置工作进程数。

worker_connections 1024:每个 worker 最大连接数。

sendfile on:启用零拷贝,提高文件传输效率。

tcp_nopush, tcp_nodelay:优化 TCP 性能。

keepalive_timeout 65:合理设置连接保持时间。

  1. 安全优化

    server_tokens off:隐藏 Nginx 版本。

ssl_protocols、ssl_ciphers:只启用安全的 TLS 协议和加密算法。

HSTS:强制客户端走 HTTPS,防止降级攻击。

可选开启 HTTP Basic 认证。

  1. 压缩优化

    gzip on:开启 gzip 压缩,减少带宽占用。

gzip_types:指定压缩的内容类型。

  1. HTTP/2

    加快 HTTPS 加载速度,提升用户体验。

  2. 蹭墙缓存

1
2
3
4
location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
expires 30d;
access_log off;
}

HTTP验证

下载安装 htpasswd

1
2
3
4
5
6
apt install apache2-utils -y

# 生成密码文件
htpasswd -c -d /etc/nginx/.htpasswd user # user 是用户名
# 输入密码

生成的密码文件

1
2
# htpasswd
users:$apr1$ZQx2j8wN$2eqFlYE6fVnK/a8dQsAOZ/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
events {}

http {
server {
listen 443 ssl; # 这是HTTPS的默认端口,80为HTTP的默认端口
server_name nginx.baby; # 填写绑定证书的域名

ssl_certificate /etc/nginx/ssl/nginx.baby.pem; # 证书文件位置(.crt文件, .pen文件)
ssl_certificate_key /etc/nginx/ssl/nginx.baby.key; # 私钥文件位置(.key文件)

location / {
# auth_basic "请输入用户名密码"; # 提示,可省略
# auth_basic_user_file /etc/nginx/.htpasswd; # 密码文件位置(.htpasswd文件)

root /usr/share/nginx/html;
index index.html;
}
}
server {
listen 80;
return 301 https://$host$request_uri; # 将HTTP请求全部重定向到HTTPS
}

}

Docker 容器的 nginx 配置

1
2
3
4
5
6
7
8
9
docker run -itd \
--name test_nginx_ssl \
--restart unless-stopped \
-p 80:80 -p 443:443 \
-v /apps/htpass/nginx.conf:/etc/nginx/nginx.conf:ro \
-v /apps/htpass/htpasswd:/etc/nginx/.htpasswd:ro \
-v /apps/htpass/html:/usr/share/nginx/html:ro \
-v /apps/htpass/ssl:/etc/nginx/ssl:ro \
nginx

Python打包工具

pyinstaller

1
pip install pyinstaller
1
2
3
4
5
6
7

# 存放路径
# C:\Users\123\Desktop\pyinstaller
cd C:\Users\123\Desktop\test

pyinstaller -F -i <图标的文件名.ico> --add-data "<图标文件夹>;<图标文件夹>" --add-data "<音乐文件夹>;<音乐文件夹>" <主程序.py>

Nginx删除脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#!/bin/bash

# 颜色
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
BLUE='\033[0;34m'
PURPLE='\033[0;35m'
CYAN='\033[0;36m'
NC='\033[0m'

echo -e "${GREEN}=== 开始完全卸载 nginx ===${NC}"

# 停止服务
echo -e "${YELLOW}1. 停止 nginx 服务...${NC}"
sudo systemctl stop nginx 2>/dev/null || true # true 表示忽略错误
sudo systemctl disable nginx 2>/dev/null || true

# 卸载软件包
echo -e "${YELLOW}2. 卸载 nginx 软件包...${NC}"
sudo apt remove --purge -y nginx nginx-common nginx-full nginx-core 2>/dev/null || true
sudo apt autoremove --purge -y
sudo apt autoclean

# 删除配置和数据目录
echo -e "${YELLOW}3. 删除配置文件和目录...${NC}"
sudo rm -rf /etc/nginx
sudo rm -rf /var/log/nginx
sudo rm -rf /var/cache/nginx
sudo rm -rf /var/run/nginx.pid
sudo rm -rf /var/lib/nginx

# 删除服务文件
echo -e "${YELLOW}4. 删除服务文件...${NC}"
sudo rm -f /lib/systemd/system/nginx.service
sudo rm -f /etc/systemd/system/nginx.service
sudo rm -f /etc/systemd/system/multi-user.target.wants/nginx.service

# 删除用户和组
echo -e "${YELLOW}5. 删除 nginx 用户和组...${NC}"
sudo deluser nginx 2>/dev/null || true
sudo delgroup nginx 2>/dev/null || true

# 重新加载 systemd
echo -e "${YELLOW}6. 重新加载 systemd...${NC}"
sudo systemctl daemon-reload

# 检查残留
echo -e "${YELLOW}7. 检查残留文件...${NC}"
echo -e "${YELLOW}检查是否还有 nginx 进程:${NC}"
ps aux | grep nginx | grep -v grep || echo -e "${RED}没有 nginx 进程${NC}"

echo -e "${YELLOW}检查是否还有 nginx 包:${NC}"
dpkg -l | grep nginx || echo -e "${RED}没有 nginx 包${NC}"

echo -e "${YELLOW}检查端口 80 使用情况:${NC}"
sudo netstat -tlnp | grep :80 || echo -e "${RED}端口 80 未被占用${NC}"

echo -e "${GREEN}=== nginx 卸载完成 ===${NC}"
echo -e "${YELLOW}建议重启系统以确保完全清理${NC}"

Python 爬取番茄小说

首先我们先需要准备所需模块

1
2
3
4
5
6
7
8
pip install parsel, html/xml、数据提取库
pip install fontTools, 文字处理模块
pip install ddddocr, 验证码识别模块
pip install brotli, 解压缩数据模块
pip install lxml, html解析模块
pip install tqdm, 进度条模块
pip install requests, 网络请求模块
pip install --upgrade pillow, 图像请求模块

爬取思路

  1. 首先我们先找到对应的小说网站

    https://fanqienovel.com/page/7075952796322761739

注意:后面的网页数字,这可能是页面唯一变换的地方,可以尝试多个章节的网页对比

  1. 通过 F12 查看网页源代码,找到对应的小说内容,通过正则提取出小说内容

  2. 通过正则提取出小说章节对应的 ID 号

代码

<./fanqie_xiaoshuo.py>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# -*- coding: utf-8 -*- 目前版本不需要
import requests
from tqdm import tqdm
import parsel
import re

font_dic = { 58344: 'd', 58345: '在', 58346: '主', 58347: '特', 58348: '家', 58349: '军', 58350: '然', 58351: '表', 58352: '场', 58353: '4', 58354: '要', 58355: '只', 58356: 'v', 58357: '和', 58359: '6', 58360: '别', 58361: '还', 58362: 'g', 58363: '现', 58364: '儿L', 58365: '岁', 58368: '此', 58369: '象', 58370: '月', 58371: '3', 58372: '出', 58373: '战', 58374: '工', 58375: '相', 58376: 'o', 58377: '男', 58378: '直', 58379: '失', 58380: '世', 58381: 'F', 58382: '都', 58383: '平', 58384: '文', 58385: '什', 58386: 'v', 58387: 'o', 58388: '将', 58389: '真', 58390: 't', 58391: '那', 58392: '当', 58394: '会', 58395: '立', 58396: '些', 58397: 'u', 58398: '是', 58399: '十', 58400: '张', 58401: '学', 58402: '气', 58403: '大', 58404: '爱', 58405: '两', 58406: '命', 58407: '全', 58408: '后', 58409: '东', 58410: '性', 58411: '通', 58412: '被', 58413: '1', 58414: '它', 58415: '乐', 58416: '接', 58417: '而', 58418: '感', 58419: '车', 58420: '山山', 58421: '公', 58422: '了', 58423: '常', 58424: '以', 58425: '何', 58426: '可', 58427: '话', 58428: '先', 58429: 'p', 58430: 'i', 58431: '叫', 58432: '轻', 58433: 'm', 58434: '上', 58435: 'w', 58436: '着', 58437: '变', 58438: '尔', 58439: '快', 58440: 'l', 58441: '个', 58442: '说', 58443: '少', 58444: '色', 58445: '里', 58446: '安', 58447: '花', 58448: '远', 58449: '7', 58450: '难', 58451: '师', 58452: '放', 58453: 't', 58454: '报', 58455: '认', 58456: '面', 58457: '道', 58458: 's', 58460: '克', 58461: '地', 58462: '度', 58463: 'l', 58464: '好', 58465: '机', 58466: 'u', 58467: '民', 58468: '写', 58469: '把', 58470: '万', 58471: '同', 58472: '水', 58473: '新', 58474: '没', 58475: '书', 58476: '电', 58477: '吃', 58478: '像', 58479: '斯', 58480: '5', 58481: '为', 58482: 'y', 58483: '白', 58484: '几', 58485: '日', 58486: '教', 58487: '看', 58488: '但', 58489: '第', 58490: '加', 58491: '候', 58492: '作', 58493: '上', 58494: '拉', 58495: '住', 58496: '有', 58497: '法', 58498: 'r', 58499: '事', 58500: '应', 58501: '位', 58502: '利', 58503: '你', 58504: '声', 58505: '身', 58506: '国', 58507: '问', 58508: '马', 58509: '女', 58510: '他', 58511: 'y', 58512: '比', 58513: '父', 58514: 'x', 58515: 'a', 58516: 'h', 58517: 'n', 58518: 's', 58519: 'x', 58520: '边', 58521: '美', 58522: '对', 58523: '所', 58524: '金', 58525: '活', 58526: '回', 58527: '意', 58528: '到', 58529: 'z', 58530: '从', 58531: 'j', 58532: '知', 58533: '又', 58534: '内', 58535: '因', 58536: '点', 58537: 'q', 58538: '三', 58539: '定', 58540: '8', 58541: 'r', 58542: 'b', 58543: '正', 58544: '或', 58545: '夫', 58546: '向', 58547: '德', 58548: '听', 58549: '更', 58551: '得', 58552: '告', 58553: '并', 58554: '本', 58555: 'q', 58556: '过', 58557: '记', 58558: 'L', 58559: '让', 58560: '打', 58561: 'f', 58562: '人', 58563: '就', 58564: '者', 58565: '去', 58566: '原', 58567: '满', 58568: '体', 58569: '做', 58570: '经', 58571: 'k', 58572: '走', 58573: '如', 58574: '孩', 58575: 'c', 58576: 'g', 58577: '给', 58578: '使', 58579: '物', 58581: '最', 58582: '笑', 58583: '部', 58585: '员', 58586: '等', 58587: '受', 58588: 'k', 58589: '行', 58590: '一', 58591: '条', 58592: '果', 58593: '动', 58594: '光', 58595: '门', 58596: '头', 58597: '见', 58598: '往', 58599: '自', 58600: '解', 58601: '成', 58602: '处', 58603: '天', 58604: '能', 58605: '于', 58606: '名', 58607: '其', 58608: '发', 58609: '总', 58610: '母', 58611: '的', 58612: '死', 58613: '手', 58614: '入', 58615: '路', 58616: '进', 58617: '心', 58618: '来', 58619: 'h', 58620: '时', 58621: '力', 58622: '多', 58623: '开', 58624: '已', 58625: '许', 58626: 'd', 58627: '至', 58628: '由', 58629: '很', 58630: '界', 58631: 'n', 58632: '小', 58633: '与', 58634: 'z', 58635: '想', 58636: '代', 58637: '么', 58638: '分', 58639: '生', 58640: '口', 58641: '再', 58642: '妈', 58643: '望', 58644: '次', 58645: '西', 58646: '风', 58647: '种', 58648: '带', 58649: 'J', 58651: '实', 58652: '情', 58653: '才', 58654: '这', 58656: 'e', 58657: '我', 58658: '神', 58659: '格', 58660: '长', 58661: '觉', 58662: '问', 58663: '年', 58664: '眼', 58665: '无', 58666: '不', 58667: '亲', 58668: '关', 58669: '结', 58670: '0', 58671: '友', 58672: '信', 58673: '下', 58674: '却', 58675: '重', 58676: '己', 58677: '老', 58678: '2', 58679: '音', 58680: '字', 58681: 'm', 58682: '呢', 58683: '明', 58684: '之', 58685: '前', 58686: '高', 58687: 'p', 58688: 'b', 58689: '目', 58690: '太', 58691: 'e', 58692: '9', 58693: '起', 58694: '棱', 58695: '她', 58696: '也', 58697: 'w', 58698: '用', 58699: '方', 58700: '子', 58701: '英', 58702: '每', 58703: '理', 58704: '便', 58705: '四', 58706: '数', 58707: '期', 58708: '中', 58709: 'c', 58710: '外', 58711: '样', 58712: 'a', 58713: '海', 58714: '们', 58715: '任'}

url = "https://fanqienovel.com/page/7075952796322761739"

headers = {
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36 Edg/137.0.0.0",
"Connection": "keep-alive",
}

r = requests.get(url, headers=headers).text

# 利用re正则表达式提取章节ID数据
# ID_list = re.findall('<a href="/reader/(\d+)" class="chapter-item-title" target="_blank">', r)
ID_list = re.findall('"itemId":"(\d+)"', r)
# with open('fanqie.txt', mode='a', encoding='utf-8') as f:
# f.write(r)
# 获取小说名
title_name = re.findall('"bookName":"(.*?)"', r)[0]
print(f'正在爬取{title_name}请稍等...')
# print(ID_list)

for i in tqdm(ID_list):
# 获取所有ID章节链接
ID_url = f'https://fanqienovel.com/reader/{i}?enter_from=page'
# print(ID_url)
# 对连接发送请求
ID_r = requests.get(ID_url, headers=headers)
# 获取小说章节页面的html代码
html = ID_r.text
# 用css选择器取值,但是css不能对字符串取值,所以需要用parsel模块解析后再取值
selector = parsel.Selector(html)
# 利用css选择器提取小说标题
title = selector.css('.muye-reader-title::text').get()
# 利用css选择器提取小说的文本内容
text_content = selector.css('.muye-reader-content p::text').getall()
# print(text_content)
text = "\n\n".join(text_content)
# print(text)
# 定义一个空字符novel
novel = ''
# 对加密文字进行替换
for t in text:
try:
font = font_dic[ord(t)]
# print(font, end="")
novel += font
except:
font = t
novel += font
# print(font, end="")
with open(title_name + '.txt', mode='a', encoding='utf-8') as f:
f.write(title)
f.write("\n\n")
f.write(novel)
f.write("\n\n")

<./font.py>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
import sys
from io import BytesIO
from PIL import Image, ImageDraw, ImageFont
from fontTools.ttLib import TTFont
import ddddocr
import brotli
try:
import brotli
except ImportError:
print("错误:缺少 'brotli' 模块,WOFF2 解码需要此模块。请使用以下命令安装:pip install brotli")
sys.exit(1)

def font_to_img(_code, font_path):
"""将 Unicode 字符转换为使用指定字体的图像"""
img_size = 1024
img = Image.new('1', (img_size, img_size), 255) # 创建二值图像
draw = ImageDraw.Draw(img)
try:
font = ImageFont.truetype(font_path, int(img_size * 0.7))
except OSError as e:
print(f"错误:无法加载字体文件 '{font_path}':{e}")
sys.exit(1)

txt = chr(_code)
bbox = draw.textbbox((0, 0), txt, font=font)
x = bbox[2] - bbox[0]
y = bbox[3] - bbox[1]
draw.text(((img_size - x) // 2, (img_size - y) // 7), txt, font=font, fill=0)
return img

def identify_word(font_path):
"""使用 OCR 识别字体文件中的字符并创建映射"""
font_mapping = {}
try:
font = TTFont(font_path)
except Exception as e:
print(f"错误:无法处理字体文件 '{font_path}':{e}")
sys.exit(1)

ocr = ddddocr.DdddOcr() # 初始化 OCR
for cmap_code, glyph_name in font.getBestCmap().items():
bytes_io = BytesIO()
pil = font_to_img(cmap_code, font_path)
pil.save(bytes_io, format='PNG')
try:
word = ocr.classification(bytes_io.getvalue())
print(f"Unicode: {cmap_code} - Glyph: {glyph_name} - OCR 结果: {word}")
if word: # 仅将有效 OCR 结果添加到映射
font_mapping[cmap_code] = word
except Exception as e:
print(f"处理 Unicode {cmap_code} 时出错:{e}")
continue

return font_mapping

if __name__ == '__main__':
font_file = 'dc027189e0ba4cd.woff2'
mapping = identify_word(font_file)
print('最终字体映射:', mapping)

json 解析

解析 json 数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
package main

import (
"encoding/json"
"fmt"
)

func main() {
jsonData := `{
"status": "success",
"timestamp": "2025-07-21T10:00:00Z",
"data": [
{
"host": "server-01",
"metrics": {
"cpu": {
"usage": 35.6,
"cores": 4
},
"memory": {
"total": 32768,
"used": 16384,
"unit": "MB"
},
"disk": [
{
"mount": "/",
"total": 512000,
"used": 400000,
"unit": "MB"
}
],
"network": {
"eth0": {
"rx_bytes": 123456789,
"tx_bytes": 987654321
}
}
}
}
]
}`
var result map[string]interface{}
err := json.Unmarshal([]byte(jsonData), &result)
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Println("Result:", result)
}

Go 指针使用

指针的用法

1
2
3
4
5
6
7
8
func main() {
a := 10
b := &a
fmt.Println(*b)
*b = 20
fmt.Println(a)
// 10 20
}
  1. 在函数里修改传入的变量值
1
2
3
4
5
6
7
8
9
func changeValue(x *int) {
*x = 200
}

func main() {
a := 100
changeValue(&a)
fmt.Println(a)
}
  1. 提高性能(避免大对象复制)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
type User struct{
Name string
Age int
}
func PrintUser(u *User) {
fmt.Println(u.Name, u.Age)
}

func main() {
u := User{
Name: "Tom",
Age: 10,
}
PrintUser(&u)
u.Name = "Jack"
PrintUser(&u)
}
  1. 和结构体方法有关
    如果需要修改结构体里的值,方法接收器要用指针
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
type Counter struct {
Count int
}

func (c *Counter) Add() {
c.Count += 1
}

func main() {
c := Counter{
10,
}
c.Add()
fmt.Println(c.Count)
// 11
}

总结

用法 示例 说明
获取地址 p := &a 获取变量 a 的地址
取地址的值 *p 获取指针 p 指向的值
修改值 *p = 123 通过指针修改原变量
函数传指针 func f(p *int) 在函数中修改外部变量
Gin 指针用法 func(c *gin.Context) 操作请求上下文必须用指针

smart 磁盘检查

smart 介绍

smartclt

使用

1
2
3
4
5
6
lsblk -d -o NAME,SIZE,MODEL
NAME SIZE MODEL
sda 278.9G PERC H330 Mini
sdb 5.5T PERC H330 Mini
sdc 5.5T PERC H330 Mini
sdd 5.5T PERC H330 Mini
1
smartctl -a /dev/sda

系统使用了 DELL 或 MegaRAID(如 PERC 控制器) 管理磁盘;
/dev/sdb 实际只是一个 RAID 虚拟设备,smartctl 无法直接对它读 S.M.A.R.T 信息;
smartctl 需要你告诉它 RAID 卡后面“具体是哪个物理盘”——通过 -d megaraid,N 参数。

1
smartctl -a -d megaraid,1 /dev/sdb | grep -E "^SMART Health Status" | awk -F ":" '{print $NF}' | tr -d " "

Docker 安装 MySQL

一、用 Docker 安装 MySQL 8.0 的基本命令

1
2
3
4
5
docker run -d \
--name mysql8 \
-e MYSQL_ROOT_PASSWORD=song@123 \
-p 3306:3306 \
mysql:8.0

说明:

  • -d:后台运行容器。

  • –name mysql8:容器名为 mysql8。

  • -e MYSQL_ROOT_PASSWORD=song@123:设置 root 用户密码。

  • -p 3306:3306:将宿主机 3306 端口映射到容器内的 3306 端口。

  • mysql:8.0:使用官方 MySQL 8.0 镜像。

-v 参数解释

-v 是 挂载卷(volume) 的意思,让容器里的文件和你本地的文件夹互通。你可以:

1
-v <主机路径>:<容器路径>
1
-v /my/mysql/data:/var/lib/mysql

就会把宿主机 /my/mysql/data 文件夹挂到容器里的 /var/lib/mysql,也就是 MySQL 的数据目录。

-v 方式导入初始化数据

MySQL 支持在容器启动时,自动执行挂载目录中 .sql 文件来初始化数据库。

  1. 准备 SQL 文件:
1
2
3
4
5
6
-- 文件名:init.sql
CREATE DATABASE testdb;
USE testdb;
CREATE TABLE user (id INT PRIMARY KEY, name VARCHAR(20));
INSERT INTO user VALUES (1, 'Alice'), (2, 'Bob');

1
2
3
4
5
6
docker run -d \
--name mysql8-init \
-e MYSQL_ROOT_PASSWORD=song@123 \
-p 3306:3306 \
-v /home/user/mysql-init:/docker-entrypoint-initdb.d \
mysql:8.0

crontab 定时任务

crontab 设置定时任务

1
2
3
crontab -l # 查看当前用户的定时任务

crontab -e # 编辑定时任务
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 每分钟执行一次:
* * * * * /path/to/script.sh
# 所有时间字段都是 *,表示每分钟运行。每天凌晨 2:30 执行:
30 2 * * * /path/to/backup.sh
# 分钟=30,小时=2,其他字段任意。
# 每周一 8:00 执行:
0 8 * * 1 /path/to/weekly_task.sh
# 分钟=0,小时=8,星期=1(周一)。
# 每 10 分钟执行一次:
*/10 * * * * /path/to/check_status.sh
# 分钟字段 */10 表示每 10 分钟。
# 每月 1 号和 15 号的 9:00 执行:
0 9 1,15 * * /path/to/monthly_report.sh
# 日期字段 1,15 表示每月 1 号和 15 号。
# 工作日的每天下午 3:00 执行:
0 15 * * 1-5 /path/to/workday_task.sh
# 星期字段 1-5 表示周一到周五。
# 每小时的第 0 分钟和第 30 分钟执行:
0,30 * * * * /path/to/half_hour_task.sh
分钟字段 0,30 表示每小时的第 0 分钟和第 30 分钟。
1
2
3
4
5
6
7
8
* * * * * root command-to-execute
| | | | | |
| | | | | +--- 用户名
| | | | +----- 星期几 (0 - 7)(0 和 7 都表示星期天)
| | | +------- 月份 (1 - 12)
| | +--------- 日期 (1 - 31)
| +----------- 小时 (0 - 23)
+------------- 分钟 (0 - 59)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#!/bin/bash

# 配置项
DB_USER="root"
DB_PASSWORD="你的密码"
DB_NAME="你的数据库名"
BACKUP_DIR="/data/mysql_backup"

# 日期格式
DATE=$(date +"%Y-%m-%d")
FILENAME="${DB_NAME}_${DATE}.sql"
TARFILE="${FILENAME}.tar.gz"

# 创建备份目录(如果不存在)
mkdir -p "$BACKUP_DIR"

# 执行备份
mysqldump -u"$DB_USER" -p"$DB_PASSWORD" "$DB_NAME" > "$BACKUP_DIR/$FILENAME"

# 压缩备份文件
tar -czf "$BACKUP_DIR/$TARFILE" -C "$BACKUP_DIR" "$FILENAME"

# 删除原始 .sql 文件
rm -f "$BACKUP_DIR/$FILENAME"

# 删除7天前的备份
find "$BACKUP_DIR" -type f -name "*.tar.gz" -mtime +7 -exec rm -f {} \;

echo "[`date`] MySQL 备份完成: $TARFILE"

1
2
3
[client]
user=root
password=你的密码

chmod 600 ~/.my.cnf

然后脚本里就可以直接使用

1
mysqldump "$DB_NAME" > "$BACKUP_DIR/$FILENAME"

chmod +x /usr/local/bin/mysql_backup.sh

1
0 2 * * * /usr/local/bin/mysql_backup.sh >> /var/log/mysql_backup.log 2>&1

MySQL 客户端程序(如 mysql, mysqldump)会自动查找并读取默认配置文件路径中的
.my.cnf,你不需要在脚本里手动“引用”