VPS基本部署环境的搭建与配置

  1. 1. VPS及域名的购买和基本配置
    1. 1.1 VPS的购买及基本配置
      1. 1.1.1 购买Banwagon VPS
      2. 1.1.2 使用KiWiVM面板管理VPS
    2. 1.2 SSH远程连接VPS
      1. 1.2.1 使用FinallShell远程连接
      2. 1.2.2 设置代理访问被墙服务器
    3. 1.3 购买NameSilo域名
    4. 1.4 NameSilo域名解析
    5. 1.5 宝塔面板的搭建及使用
      1. 1.5.1 宝塔面板简介
      2. 1.5.2 安装宝塔面板
      3. 1.5.3 修改面板基本设置
      4. 1.5.4 安装LNMP/LAMP开发环境
      5. 1.5.5 卸载宝塔面板
    6. 1.6 服务器之间的数据迁移
      1. 1.6.1 通过KiWiVM管理面板进行迁移
      2. 1.6.2 通过宝塔面板进行迁移
  2. 2. Linux常用命令
    1. 2.1 Linux基本命令使用
      1. 2.1.1 文件目录
      2. 2.1.2 拷贝移动
      3. 2.1.3 文件内容
      4. 2.1.4 远程管理
      5. 2.1.5 权限管理
      6. 2.1.6 下载安装
      7. 2.1.7 压缩解压
      8. 2.1.8 系统管理
      9. 2.1.9 其他常用
    2. 2.2 Linux常用操作
      1. 2.2.1 常用命令安装
      2. 2.2.2 使用Shell脚本
      3. 2.2.3 放行指定端口
      4. 2.2.4 扩充SWAP空间
      5. 2.2.5 Crontab定时任务
      6. 2.2.6 设置开机自启
      7. 2.2.7 修改系统时间
      8. 2.2.8 将Python升级为3.x
      9. 2.2.9 安装pip
      10. 2.2.10 安装jdk
      11. 2.2.11 jar包部署
      12. 2.2.12 kill指定端口号的进程
      13. 2.2.13 监控进程状态
      14. 2.2.14 安装Node.js和npm
      15. 2.2.15 统计文件及文件夹个数
      16. 2.2.16 拷贝同步大量文件
      17. 2.2.17 在服务器之间传输文件或者文件夹
      18. 2.2.18 递归删除某目录下指定扩展名的文件
      19. 2.2.19 安装go及bee工具
      20. 2.2.20 磁盘空间占用分析
      21. 2.2.21 查看GPU基础信息
    3. 2.3 Linux运维脚本
      1. 2.3.1 自动重启挂掉的jar包
      2. 2.3.2 jar包运维脚本
  3. 3. 科学上网环境的搭建
    1. 3.1 SSR服务器端搭建
      1. 3.1.1 ShadowsocksR简介
      2. 3.1.2 一键脚本搭建SSR服务
    2. 3.2 Trojan-Go服务器端搭建
      1. 3.2.1 Trojan-Go简介
      2. 3.2.2 一键脚本搭建Trojan-Go服务
  4. 4. 版本控制环境搭建
    1. 4.1 Git环境搭建
      1. 4.1.1 安装配置Git
      2. 4.1.2 创建用户并赋予权限
      3. 4.1.3 初始化git仓库并配置SSH
      4. 4.1.4 本地连接远程仓库
    2. 4.2 SVN环境搭建
      1. 4.2.1 安装配置SVN
      2. 4.2.2 SVN权限控制
      3. 4.2.3 SVN开机自启
  5. 5. 部署容器环境搭建
    1. 5.1 Docker简介
      1. 5.1.1 Docker是什么
      2. 5.1.2 Docker的架构
      3. 5.1.3 Docker Compose是什么
      4. 5.1.4 Docker与Docker Compose的区别
      5. 5.1.5 直接安装和Docker安装的区别
    2. 5.2 Docker环境搭建
      1. 5.2.1 卸载原先安装的Docker
      2. 5.2.2 安装Docker
      3. 5.2.3 Docker常用命令
      4. 5.2.4 Docker异常情况
    3. 5.3 Docker Compose环境搭建
    4. 5.4 通过Dockerfile自动构建镜像
      1. 5.4.1 使用Docker部署Springboot项目
      2. 5.4.2 使用Docker部署Flask项目
    5. 5.5 将已有容器部署到其他服务器
  6. 6. 项目运行环境搭建
    1. 6.1 Docker-MySQL环境搭建
      1. 6.1.1 搜索MySQL镜像
      2. 6.1.2 拉取MySQL镜像
      3. 6.1.3 创建实例容器并运行
      4. 6.1.4 创建数据库及用户
      5. 6.1.5 数据库的备份与恢复
      6. 6.1.6 数据库的定时备份
    2. 6.2 Docker-Nginx环境搭建
      1. 6.2.1 获取Nginx镜像
      2. 6.2.2 创建Nginx容器
      3. 6.2.3 修改Nginx配置文件
      4. 6.2.4 测试Nginx环境
      5. 6.2.5 搭建过程踩的坑
      6. 6.2.6 Nginx的一些其他管理命令
    3. 6.3 Docker-Redis环境搭建
      1. 6.3.1 获取Redis镜像
      2. 6.3.2 创建Redis容器
      3. 6.3.3 Redis数据库的可视化连接
    4. 6.4 Docker-Oracle环境搭建
      1. 6.4.1 拉取镜像并运行容器
      2. 6.4.2 进入容器进行配置
      3. 6.4.3 修改密码创建用户
      4. 6.4.4 用连接工具登录
    5. 6.5 Docker-ElasticSearch环境搭建
      1. 6.5.1 拉取镜像并运行容器
      2. 6.5.2 进入容器进行配置
      3. 6.5.3 ES的导入与导出
      4. 6.5.4 ES的定期自动备份
    6. 6.6 Docker-Neo4j环境搭建
      1. 6.6.1 拉取镜像并运行容器
      2. 6.6.2 neo4j的可视化查看
  7. 7. 网站环境搭建
    1. 7.1 申请泛域名SSL证书并开启HTTPS
      1. 7.1.1 安装 acme.sh
      2. 7.1.2 生成SSL泛域名证书
      3. 7.1.3 acme.sh的一些其他管理命令
      4. 7.1.4 给网站开启HTTPS
    2. 7.2 网站开启CDN服务
      1. 7.2.1 CDN与Cloudflare是什么
      2. 7.2.2 开启 Cloudflare CDN 服务
      3. 7.2.3 CDN缓存问题
    3. 7.3 Git Hooks自动部署
      1. 7.3.1 Git Hooks简介
      2. 7.3.2 新建网站
      3. 7.3.3 修改Nginx配置
      4. 7.3.4 配置Git Hooks
    4. 7.4 给网站设置反向代理
  8. 8. 开发辅助环境搭建
    1. 8.1 搭建ReverseProxy破解JRebel热部署插件
      1. 8.1.1 在VPS搭建ReverseProxy服务
      2. 8.1.2 配置开机自启、HTTPS及反向代理
    2. 8.2 搭建ProxyPool爬虫代理IP池
      1. 8.2.1 搭建Redis数据库
      2. 8.2.2 使用Docker部署ProxyPool项目
      3. 8.2.3 配置HTTPS及反向代理
      4. 8.2.4 ProxyPool的API服务
      5. 8.2.5 在爬虫中使用ProxyPool
    3. 8.3 搭建EMQX物联网MQTT消息服务器
      1. 8.3.1 使用Docker搭建EMQX消息服务器
      2. 8.3.2 与之配套的客户端MQTTX
    4. 8.4 Docker可视化工具Portainer的部署
      1. 8.4.1 Portainer简介
      2. 8.4.2 Portainer部署
  9. 9. 参考资料

1. VPS及域名的购买和基本配置

1.1 VPS的购买及基本配置

1.1.1 购买Banwagon VPS

如果是自己玩的话,推荐购买国外VPS,搭网站不用备案,带宽足,价格低廉。国内阿里云、腾讯云、百度云等大厂真是一言难尽,上述国外VPS的优点取反就是国内VPS的缺点,国内VPS看似便宜,磁盘空间也足,但同价位VPS的带宽是MB级的,用起来慢的一批,要想快就要买高配的,算下来价格比国外的还贵。当然如果是商业用途还是老老实实使用国内VPS厂商的吧,延迟会低一些,该备案备案。

推荐老牌大厂Banwagon,支持支付宝付款,且新用户购买后1个月内可以退款。购买时建议使用循环优惠码(后续每次续订都会享受折扣),一般每年黑色星期五(相当于国外的双11)会放出来最大力度的优惠码。这里放一个平时的循环优惠码,如果失效了请自行搜索。

1
循环优惠码:BWH3HYATVBJW(6.58%)

Banwagon

购买后会往你的邮箱里发送:“发票”,“IP、端口号、root密码”,KiWiVM管理面板地址等必要信息。

1.1.2 使用KiWiVM面板管理VPS

我们打开管理面板 KiWiVM,重置一个KiWiVM密码(邮箱验证),然后输入IP和刚刚重置的KiWiVM密码即可登录。

KiWiVM管理面板

在此点击Install new OS,选择一个合适的系统镜像进行安装,我选择的是Debian 10 x86_64,下文所有的操作命令也都是基于该系统的,如有不同请自行查阅。

VPS因搭建并使用科学上网导致被墙

1.2 SSH远程连接VPS

1.2.1 使用FinallShell远程连接

然后就可以使用FinallShell、Xshell等工具ssh远程连接到该服务器了,我这里建议使用FinallShell(它包含了Xshell和Xftp的功能,还不用破解),界面如下所示:

FinallShell

名称随便填(有多个服务器的话建议标注上IP以区分),主机填写服务器IP,端口填写服务器端口,用户名填root,密码填root密码。

解决FinallShell退格乱码问题:选项——终端——Backspace退格键选择ASCIl-Backspace,Delete删除键选择ASCll-Delete

1.2.2 设置代理访问被墙服务器

如果服务器被墙了(连接时报错:Session.connect xxx Need Username/Password authentication),还可通过添加代理服务器访问(前提是电脑上装有可用的代理工具,如Clash、SSR等)

名称随便填,类型选HTTP,主机填127.0.0.1,端口号一般是1080(端口根据你代理软件的配置来填)

1.3 购买NameSilo域名

NameSilo是一家国外的知名域名服务注册商,价格便宜而且非常可靠,管理也很方便,支持支付宝付款。这家有很多首年1美刀廉价域名,当然一般都是些不知名的域名(我们所熟知的.com.cn域名一般价格很贵),如果是自己玩的话买个廉价域名就好了。下面放一个优惠1美刀的优惠码(优惠后的实际购买价格不低于1美刀,例如你买了个1.5美刀的域名,使用该优惠码只能优惠至1美刀),如果失效了自行搜索。

1
idcspy2020(优惠1美刀) 

1.4 NameSilo域名解析

购买完域名之后,首先要做的事儿就是域名解析(说白了就是把域名与你的服务器IP进行绑定)

[1] 打开NameSilo官网,依次完成下图所示的三步操作

NameSilo域名解析1

[2] Type选A,Address/Value处填服务器IP,TTL填3600即可(是指全国各地的DNS服务器中缓存解析结果的时间周期)

NameSilo域名解析2

注:一个二级域名可以绑若干个三级域名;一般十分钟左右 DNS 解析记录会生效(可以直接在cmd里ping域名验证是否解析成功)

1.5 宝塔面板的搭建及使用

1.5.1 宝塔面板简介

宝塔面板是一个广东堡塔安全技术有限公司开发的一款LInux管理面板,分为商业版和免费版,有较好的图形化交互界面,可以傻瓜式的管理Linux服务器,适合小白用户自己折腾着玩。生产环境勿用宝塔面板进行部署,有一些意想不到的bug,同时也存在安全隐患,老老实实用命令手动部署。

1.5.2 安装宝塔面板

以下以我所使用过的Debian10和Centos7为例,其余发行版的安装方式参见:宝塔Linux面板安装教程

Debian 10:

1
wget -O install.sh http://download.bt.cn/install/install-ubuntu_6.0.sh && bash install.sh

Centos 7:

1
yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh

最后得到了宝塔面板的登陆信息,将其保存下来

1
2
3
Bt-Panel: http://IP/********
username: ********
password: ********

注:如果忘记了可以使用bt default命令进行查看(只能看到面板地址和初始的账号及密码,如果改过了就只能重置了)

宝塔Linux面板

1.5.3 修改面板基本设置

进入宝塔面板的第一件事就是修改面板端口、面板用户、面板密码等关键信息,否则存在安全隐患,其他面板配置根据自己需要来就好。

  • Step1:安全——防火墙——放行指定端口,顺便把默认的8888端口关掉。

  • Step2:面板设置——修改面板端口、面板用户、面板密码等关键信息。

1.5.4 安装LNMP/LAMP开发环境

刚进来宝塔面板的时候会提示安装LNMP或者LAMP环境,根据需求勾选部分即可(忘记勾的可以去软件商店那里搜索下载),建议使用较慢的编译安装。

LNMP和LAMP环境

1.5.5 卸载宝塔面板

1
2
$ wget http://download.bt.cn/install/bt-uninstall.sh
$ sh bt-uninstall.sh

1.6 服务器之间的数据迁移

1.6.1 通过KiWiVM管理面板进行迁移

俩服务器之间可以直接通过镜像同步,无需把镜像下载到本地再上传,以下方法仅适用于两台VPS都是Banwagon的。

  • 旧服务器:Snapshots——Export——复制VEID和TOKEN
  • 新服务器:Snapshots——Import Snapshots——粘贴VEID和TOKEN

1.6.2 通过宝塔面板进行迁移

使用宝塔面板进行数据迁移之前,最好给新的服务器安装上和旧服务器一样的宝塔环境,包括php、mysql版本。 网站数据一定要提前备份,防止出现意外问题。

Step1:去旧服务器安装“宝塔一键迁移”插件

  • 宝塔面板——软件商店——应用搜索——宝塔一键迁移——安装

Step2:去新服务器获取API密钥,并添加旧服务器IP至白名单

  • 宝塔面板——面板设置——打开API接口——接口密钥重置——添加旧服务器IP至白名单

Step3:去旧服务器迁出

  • 宝塔一键迁移 ——设置——填写迁出地址与API密钥 ——选择迁出数据——一键迁移

2. Linux常用命令

2.1 Linux基本命令使用

2.1.1 文件目录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
ls命令:显示指定文件或指定目录中的所有文件信息
-l:按长格式显示文件详细信息(可用于查看文件权限)
cd命令:改变当前目录为指定的目录(不指定目录参数时,进入用户的主目录)
mkdir命令:建立目录
-m 权限:按指定的权限建立目录
-p:递归建立目录
rmdir命令:删除目录(若目录不空,则删除操作不能成功)
touch命令:修改文件的修改时间和访问时间的时间标签为现在时间(若指定的文件不存在,就建立一个新的空文件)
rm命令:删除文件(可直接删除掉目录内的所有文件)
pwd命令:显示当前目录的绝对路径
tree命令:以树状图列出目录的内容
-a 显示所有文件和目录
-C 在文件和目录清单加上色彩,便于区分各种类型
-p 列出权限标示
find命令:从指定的目录开始向下查找满足条件的文件,对找到的文件执行指定操作(例如:find . -name "*.sh")
ln命令:为某一个文件或目录在另外一个位置建立一个同步的链接(类似于Win的快捷方式)
建立软链接:ln -s a目录 b目录 取消软链接 rm -rf b目录

注:/bin存放二进制可执行文件,常用命令一般都在这里。/usr 用于存放系统应用程序。

2.1.2 拷贝移动

1
2
3
4
5
6
cp命令:复制文件
cp [选项] 源文件 目标文件
cp [选项] 源文件 目标目录
mv命令:移动文件、重命名文件
mv[选项] 源文件 目标文件 (重命名文件)
mv[选项] 源文件 目标目录 (移动文件)

2.1.3 文件内容

1
2
3
4
5
6
7
8
9
cat命令:显示文件内容 (注:cat /etc/issue 查看Linux系统版本)
nano命令:编辑文件内容 [sudo] nano filename
- 想要退出,按下Ctrl+X。
- 如果你退出前没有保存所做的修改,它会提示你是否要保存。不要,请按N,反之,则按Y。
- 然后它会让你确认要保存的文件名,确认或修改后按Enter即可。
more命令:分屏显示文件内容
grep命令:在文本文件中查找与指定模式相匹配的字符串,显示含有匹配字符串的行
wc命令:显示文件的字节数、字数和行数
sort命令:对文本文件中的各行按字符顺序排序并显示

2.1.4 远程管理

1
2
3
4
5
ifconfig命令:显示或配置网络设备
ping命令:用于确定网络的连通性
ping 主机名 ping 域名 ping IP地址
ssh命令:用于安全访问远程服务器的网络协议
ssh [email protected](例:ssh [email protected]

2.1.5 权限管理

1
2
3
4
5
6
7
8
chmod命令:修改文件或目录的存取权限
-R:递归的改变指定目录及其下的文件和子目录的权限属性
umask命令:设置、显示文件创建时的权限掩码
chgrp命令:变更文件或目录的所属群组
useradd命令:建立用户帐号和创建用户的起始目录,使用权限是root
passwd命令:更改使用者的密码
userdel命令:可删除用户帐号与相关的文件
若不加参数,则仅删除用户帐号,而不删除相关文件

2.1.6 下载安装

1
2
3
4
5
6
7
8
wget命令:从网络上下载文件,wget+网址即可。
curl命令:从网络上下载文件
-o 提供名称,下载文件会以该名称保存
-O 下载文件以原始名称保存
apt-get命令:自动从互联网的软件仓库中安装、卸载、更新软件或操作系统(Debian&&ubuntu)
apt-get [选项] install|remove|update pkg1 [pkg2 ...]
yum命令:自动从互联网的软件仓库中安装、卸载、更新软件或操作系统(CentOS)
yum [选项] install|remove|update pkg1 [pkg2 ...]

2.1.7 压缩解压

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
对于.tar.xz
- xz格式(最常用,压缩率和压缩速度都较快)
压缩:tar Jcvf filename.tar.xz some filedirs
解压:tar Jxvf filename.tar.xz some filedirs
- bz2格式(最不常用,压缩率最高,压缩速度最慢)
压缩:tar jcvf filename.tar.bz2 some filedirs
解压:tar jxvf filename.tar.bz2 some filedirs
- gz格式(压缩速度最快,压缩率较低)
压缩:tar zcvf filename.tar.gz some filedirs
解压:tar zxvf filename.tar.gz some filedirs
对于.zip
压缩:zip -r myfile.zip ./*(需要先切换目录)
解压:unzip -o -d /mydir myfile.zip (-o:不提示的情况下覆盖文件,-d指定解压目录)
对于.7z
解压:7za x myfile.7z

2.1.8 系统管理

1
2
3
4
5
6
7
8
9
10
11
12
xrandr命令:调整屏幕分辨率
xrandr 查看当前屏幕支持的分辨率
xrandr -s 1920x1080 修改分辨率
top命令:默认按照CPU的占用情况,显示占用量较大的进程
free命令:显示系统当前内存的使用情况
df命令:显示文件系统的磁盘使用情况(-h选项可以以更符合阅读习惯的方式显示磁盘使用量)
ps命令:查看进程的状态
kill命令:中止进程
reboot命令:重启Linux系统
shutdown命令:关闭Linux系统
sudo命令:变更用户身份,若不指定此参数,则预设变更为root
备注:可使用“Ctrl+Z快捷键”中止命令的执行

2.1.9 其他常用

1
2
3
4
5
6
7
8
9
10
who命令:显示已登录的用户
echo命令:显示命令行中的参数字符串(如果有空格,用引号将字符串括起来)
date命令:显示、设置系统日期和时间
cal命令:显示月份和日历
man命令:显示联机手册页
exit命令:结束当前的终端会话
history命令:查看命令执行历史
history [n] 列出最近的n条命令
sleep命令:设置下一条命令执行之前暂停指定的时间 eg:sleep 5m (暂停5分钟后继续执行)
s - 秒 ,m - 分钟,h - 小时,d - 天

2.2 Linux常用操作

2.2.1 常用命令安装

查看Linux系统版本

1
$ cat /etc/issue

常用命令的安装

1
2
3
4
5
6
7
8
$ apt-get install -y sudo                                     # 安装sudo
$ sudo apt-get update # 更新apt-get
$ apt-get install -y wget # 安装wget
$ apt-get update -y && apt-get install curl -y # 安装curl
$ apt-get install xz-utils # 安装xz
$ sudo apt-get install p7zip-full # 安装7z
$ sudo apt-get install zip # 安装zip
$ sudo apt-get install tree # 安装tree

说明:如果使用 apt-get 出现 404 Not Found 错误,说明用的系统太老了,那个源已经弃用了,可以升级系统或者换源解决。

2.2.2 使用Shell脚本

Shell脚本是一个可执行文件,其中包含了多行用于命令行输入的文本,也包含了一些用于控制脚本中各行命令执行顺序的专用命令。

运行shell脚本时,必须启动其他程序来解释该脚本,这个程序在Shell脚本的首行指定。在shell提示符下输入脚本名运行脚本时,shell首先检查脚本文件的首行内容,然后启动该行中指定的解释器。

  • Shell脚本的首行格式:以#作为前缀,后面紧跟一个!,之后是解释器的完整路径。(如:#! /bin/bash
  • 文本文件必须设定执行权限,不然无法运行。(如:chmod ugo+x test.sh
  • 运行该脚本:在命令行输入./(告诉文件在当前目录下),后面紧跟脚本名。(如./test.sh)

2.2.3 放行指定端口

Step1:安装iptables(通常系统都会自带,如果没有就需要安装)

1
2
$ apt-get update
$ apt-get install iptables

Step2:放行指定端口(以8888为例)并保存放行规则。

1
2
$ iptables -I INPUT -p tcp --dport 8888 -j ACCEPT
$ iptables-save

完成上述设置便将端口的放行规则添加到了防火墙中,防火墙的一些其他命令如下:

1
2
$ iptables -L              # 查看防火墙规则
$ iptables -D INPUT 3 # 比如删除INPUT链的第3条规则

Step3:保持规则持续生效

设置完就已经放行了指定的端口,但重启后会失效,下面设置持续生效规则。

1
2
3
$ apt-get install iptables-persistent
$ netfilter-persistent save
$ netfilter-persistent reload

设置完成后指定端口就会持续放行了。

2.2.4 扩充SWAP空间

SWAP:交换分区,就是当内存不足的时候,把一部分硬盘空间虚拟成内存使用,从而解决内存容量不足的情况。

  • Step1:查看SWAP分区大小: free -h

  • Step2:创建swap分区的文件:dd if=/dev/zero of=/root/swapfile bs=1M count=1024

    注:其中 bs是每块的大小,count是块的数量,bs*count就是swap文件的大小了,这里就是1M*1024=1G。根据实际需要自行调整count的数量。此外,/root/swapfile是swap文件的路径,可以根据需求修改,后续操作的路径要与此对应。

  • Step3:格式化交换分区文件:mkswap /root/swapfile

  • Step4:启用swap分区文件:swapon /root/swapfile

  • Step5:添加开机启动:修改 /etc/fstab 文件,末尾加/root/swapfile swap swap defaults 0 0

  • Step6:再次查看SWAP分区大小: free -h,扩充完毕

2.2.5 Crontab定时任务

Debian系统自带crontab,Ubuntu的话需要自己安装,命令如下:

1
2
3
4
安装:apt-get install cron
启动:service cron start
重启:service cron restart
停止:service cron stop

crontab 相关命令

1
2
3
4
crontab [-u username]    // 省略用户表表示操作当前用户的crontab
-e (修改 crontab 文件,如果文件不存在会自动创建)
-l (显示 crontab 文件)
-r (删除 crontab 文件)

crontab 定时任务语法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# For details see man 4 crontabs
# Example of job definition:
# .---------------- minute (0 - 59)
# | .------------- hour (0 - 23)
# | | .---------- day of month (1 - 31)
# | | | .------- month (1 - 12) OR jan,feb,mar,apr ...
# | | | | .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# | | | | |
# * * * * * user-name command to be executed
定时任务的每段为:分,时,日,月,周,用户,命令
第1列表示分钟1~59 每分钟用*或者 */1表示
第2列表示小时1~23(0表示0点)
第3列表示日期1~31
第4列表示月份1~12
第5列标识号星期0~6(0表示星期天)
第6列要运行的命令

*:表示任意时间都,实际上就是“每”的意思。可以代表00-23小时或者00-12每月或者00-59分
-:表示区间,是一个范围,00 17-19 * * * cmd,就是每天17,18,19点的整点执行命令
,:是分割时段,30 3,19,21 * * * cmd,就是每天凌晨3和晚上19,21点的半点时刻执行命令
/n:表示分割,可以看成除法,*/5 * * * * cmd,每隔五分钟执行一次

crontab定时任务实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
实例1:每1分钟执行一次myCommand
* * * * * myCommand
实例2:每小时的第3和第15分钟执行
3,15 * * * * myCommand
实例3:在上午8点到11点的第3和第15分钟执行
3,15 8-11 * * * myCommand
实例4:每隔两天的上午8点到11点的第3和第15分钟执行
3,15 8-11 */2 * * myCommand
实例5:每周一上午8点到11点的第3和第15分钟执行
3,15 8-11 * * 1 myCommand
实例6:每晚的21:30重启smb
30 21 * * * /etc/init.d/smb restart
实例7:每月1、10、22日的4 : 45重启smb
45 4 1,10,22 * * /etc/init.d/smb restart
实例8:每周六、周日的1 : 10重启smb
10 1 * * 6,0 /etc/init.d/smb restart
实例9:每天18 : 00至23 : 00之间每隔30分钟重启smb
0,30 18-23 * * * /etc/init.d/smb restart
实例10:每星期六的晚上11 : 00 pm重启smb
0 23 * * 6 /etc/init.d/smb restart
实例11:每一小时重启smb
* */1 * * * /etc/init.d/smb restart
实例12:晚上11点到早上7点之间,每隔一小时重启smb
* 23-7/1 * * * /etc/init.d/smb restart

2.2.6 设置开机自启

crontab 是 Linux 下的计划任务,当时间达到我们设定的时间时,可以自动触发某些脚本的运行。其中有个特殊的任务,叫作 @reboot ,这个任务就是在系统重启之后自动运行某个脚本。

要设置开机自启,首先在任意目录创建一个shell脚本然后赋予执行权限,然后输入crontab -e在里面配置上对应的@reboot任务即可。

1
2
$ crontab -e
@reboot /myshell/auto_run_script.sh

2.2.7 修改系统时间

通过修改时区文件来修改系统时间

1
2
$ rm -rf /etc/localtime
$ ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime

2.2.8 将Python升级为3.x

Debian10 预装的 pyhton 是 2.7.16 版本,而现在很多新软件都是用 python3 编写的,有一些甚至已经不支持 Python2 了,这时候就会报一大堆错,因此建议升级到 Python3.x 版本。

Step1:下载Python3.x

1
2
$ wget https://www.python.org/ftp/python/3.7.6/Python-3.7.6.tgz
$ tar -zxvf Python-3.7.6.tgz

Step2:安装配置

1
2
$ cd Python-3.7.6/
$ ./configure

Step3:编译安装

1
2
$ make
$ make install

Step4:验证是否安装成功

1
2
3
4
$ python -V
Python 2.7.16
$ python3 -V
Python 3.7.6

一个是旧版本 2.x,另外一个是新版本 3.x

Step5:设置 3.x 为默认版本

查看 Python 的路径,在 /usr/bin 下面。可以看到 python 链接的是 python 2.7,所以,执行 python 就相当于执行 python 2.7。

将原来 python 的软链接重命名:

1
$ mv /usr/bin/python /usr/bin/python.bak

将 python 链接至 python3:

1
$ ln -s /usr/local/bin/python3 /usr/bin/python

查看 python 版本:

1
2
$ python -V
Python 3.7.6

2.2.9 安装pip

pip是一个软件包管理系统,可让您安装Python软件包。使用pip,您可以从[Python软件包索引(PyPI)和其他存储库中安装软件包。

Step1:更新软件包列表

1
$ sudo apt update

Step2:安装pip

1
$ sudo apt install python3-pip

注:如果你的python版本是2.x的话,这里的命令换成sudo apt install python-pip

Step3:查看pip3版本

1
$ pip3 --version

Step4:将 pip 链接至 pip3:

1
$ ln -s /usr/local/bin/pip3 /usr/bin/pip

Step5:查看pip版本

1
$ pip --version

2.2.10 安装jdk

jdk11(Open JDK 11):

1
2
$ sudo apt-get update
$ sudo apt-get install default-jdk

jdk8(Open JDK 8):

目前 Java OpenJDK 8 在官方 Debian Buster 存储库中不可用,我们需要使用第三方源 AdoptOpenJDK 进行安装。

1
2
3
4
5
6
$ sudo apt-get update
$ sudo apt install apt-transport-https ca-certificates wget dirmngr gnupg software-properties-common
$ wget -qO - https://adoptopenjdk.jfrog.io/adoptopenjdk/api/gpg/key/public | sudo apt-key add -
$ sudo add-apt-repository --yes https://adoptopenjdk.jfrog.io/adoptopenjdk/deb/
$ sudo apt update
$ sudo apt install adoptopenjdk-8-hotspot

安装完成后使用如下命令验证:

1
2
$ java -version
$ javac -version

如果需要卸载,可使用如下命令:

1
2
$ sudo apt remove default-jdk                // 卸载jdk11
$ sudo apt remove adoptopenjdk-8-hotspot // 卸载jdk8

2.2.11 jar包部署

Springboot项目的部署流程(用IDEA的Maven插件将其打成jar包——将jar上传到服务器——写个运行脚本并开机自启——域名解析、反向代理、HTTPS)

1
2
3
4
$ java -jar xxx.jar        // 运行jar包
$ nohup java -jar xxx.jar // 后台运行jar包
$ ps aux|grep xxx.jar // 查看指定jar的进程
$ kill -9 进程号 // 杀死指定jar进程

注:正式部署建议加上时区参数,如东8区-Duser.timezone=GMT+8,不设置的话会导致日志记录时间异常(即便修改了系统之间也没用–date命令显示的时间是对的),可能会影响问题排查及项目使用。服务器部署jar包的完整示例命令如下:

1
$ nohup java -jar -Duser.timezone=GMT+8 xxl-job-admin.jar > xxl-job-admin.log 2>&1 &

注意事项:

  • nohup加在一个命令的最前面,表示不挂断的运行命令。
  • 2>&1的意思是将标准错误(2)也定向到标准输出(1)的输出文件。
  • &加在一个命令的最后面,表示这个命令放在后台执行。

2.2.12 kill指定端口号的进程

1
2
$ lsof -i:端口号
$ kill -9 进程号

2.2.13 监控进程状态

1
ps -aux | grep 进程号

2.2.14 安装Node.js和npm

Node.js是跨平台JavaScript的运行环境,旨在在服务器端执行JavaScript代码。npm是Node.js的默认软件包管理器,可帮助开发人员共享和重用其代码。可通过以下命令进行安装:

1
2
$ sudo apt update
$ sudo apt install nodejs npm

安装后,可用以下命令进行验证:

1
2
$ nodejs --version
$ npm --version

2.2.15 统计文件及文件夹个数

1
2
3
$ ls -l | grep "^-" | wc -l   // 统计当前目录下文件的个数(不包括子目录)
$ ls -lR| grep "^-" | wc -l // 统计当前目录下文件的个数(包括子目录)
$ ls -lR | grep "^d" | wc -l // 查看某目录下文件夹的个数(包括子目录)

2.2.16 拷贝同步大量文件

rsync 是一个常用的 Linux 应用程序,用于文件同步。它可以在本地计算机与远程计算机之间,或者两个本地目录之间同步文件(但不支持两台远程计算机之间的同步)。它也可以当作文件复制工具,替代cp和mv命令。

1
2
$ sudo apt-get install rsync
$ rsync -a /olddir /newdir

2.2.17 在服务器之间传输文件或者文件夹

1
$ scp -P port /root/testfile.txt [email protected]:/root/testfile.txt

注:port是目标服务器的端口号(如果两台服务器的端口号相同,可省略该参数),[email protected]是目标服务器的用户和ip。

2.2.18 递归删除某目录下指定扩展名的文件

在删除文件之前,建议先预览文件列表(如果文件列表很长,至少部分预览):

1
$ find path/to/files -type f -regextype posix-extended -iregex '.*\.(avi|mkv|wmv|mp4)$'

上面的命令将显示要删除的文件列表。若要实际删除文件,只需在末尾添加-delete

1
$ find path/to/files -type f -regextype posix-extended -iregex '.*\.(avi|mkv|wmv|mp4)$' -delete

如果您想要查看剩余的内容,可以加个!逆匹配输出

1
$ find path/to/files -type f -regextype posix-extended ! -iregex '.*\.(avi|mkv|wmv|mp4)$'

解释说明:

  • -type f将匹配限制为仅文件(目录不会被匹配),把它放在开头而不是结尾,因为谓词的顺序对速度很重要。
  • -iregex表示不区分大小写,如果要区分的话选择-regex
  • 尽量使用 find xxx -delete来删除文件,它比 rm 命令执行速度更快且更安全。

2.2.19 安装go及bee工具

说明:bee 工具是一个为了协助快速开发 beego 项目而创建的项目,通过 bee 您可以很容易的进行 beego 项目的创建、热编译、开发、测试、和部署。

Step1:安装并配置go开发环境

1
2
3
4
5
6
7
$ sudo apt update
$ sudo apt install curl
$ curl -O https://dl.google.com/go/go1.13.3.linux-amd64.tar.gz
$ tar xvf go1.13.3.linux-amd64.tar.gz
$ sudo chown -R root:root ./go
$ sudo mv go /usr/local
$ nano ~/.profile

在配置文件末尾追加go的环境配置

1
2
3
export GOROOT=/usr/local/go
export GOPATH=$HOME/work
export PATH=$GOPATH/bin:$GOROOT/bin:$PATH

刷新.profile配置文件并验证安装是否成功

1
2
$ source ~/.profile
$ go version

Step2:bee 工具的安装

1
2
3
4
5
$ apt-get install git
$ go env -w GO111MODULE=on
$ go get -u github.com/beego/beego/v2
$ go get -u github.com/beego/bee/v2
$ bee version

说明:这里有个坑,网上给的方案大多是如下命令:

1
2
go get github.com/astaxie/beego
go get github.com/beego/bee

会耗费很长时间且遇到一些错误,无法成功安装,这是由于hcl包同样更新到了v2,所以此路径不再可用。

1
2
3
cannot find package "github.com/hashicorp/hcl/hcl/printer" in any of:
xxx\src\github.com\hashicorp\hcl\hcl\printer (from $GOROOT)
xxx\src\github.com\hashicorp\hcl\hcl\printer (from $GOPATH)

2.2.20 磁盘空间占用分析

1
2
$ du -s /* | sort -nr    // 查看哪个目录占用空间大
$ du -h --max-depth=1 // 查看当前目录下文件夹大小情况

2.2.21 查看GPU基础信息

使用 nvidia-smi 命令可以显示出当前GPU的所有基础信息。

nvidia-smi详解

解释相关参数含义:

1
2
3
4
5
6
7
8
9
10
11
12
13
GPU:本机中的GPU编号
Name:GPU 类型
Fan:风扇转速
Temp:温度,单位摄氏度
Perf:表征性能状态,从P0到P12,P0表示最大性能,P12表示状态最小性能
Pwr:Usage/Cap:能耗表示
Bus-Id:涉及GPU总线的相关信息;
Disp.A:Display Active,表示GPU的显示是否初始化
Memory-Usage:显存使用率
Volatile GPU-Util:浮动的GPU利用率
Uncorr. ECC:关于ECC的东西
Compute M.:计算模式
Processes 显示每块GPU上每个进程所使用的显存情况。

2.3 Linux运维脚本

2.3.1 自动重启挂掉的jar包

部署到服务器上的jar包有时会自己挂掉,比如当系统内存占用过高,触发了oom-killer机制,导致进程被kill。我们可以在服务器部署一个监控脚本monitor.sh,定时监测系统情况,当服务挂掉时自动重启,一定程度的保证系统的高可用性。

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
#!/bin/bash

# 变量
jarName=xxx.jar
timeZone=GMT+8
jarUrl=/myproject/xxx
webUrl=https://xxx.xxx.xxx/
logName=xxx.log

# grep -v grep: 在文档中过滤掉包含有grep字符的行
# awk '{print $2}': 按空格截取第二个
pid=`ps -ef|grep $jarName |grep -v grep| awk '{print $2}'`
# wc -l: jar包进程的数量
num=`ps -ef|grep $jarName |grep -v grep| awk '{print $2}'| wc -l`

MonitorFunction(){
# 输出文本
echo "[info]进入监控脚本"`date +'%Y-%m-%d %H:%M:%S'`
# -eq: 等于
if [[ $num -eq 0 ]]; then
echo "[error]进程不存在,重启"`date +'%Y-%m-%d %H:%M:%S'`
# >> /dev/null : jar包生成日志不打印到此脚本日志中
java -jar $jarUrl/$jarName >> /dev/null &
else
# 获取页面访问状态
# -m 10: 最多查询10s --connect-timeout 10:10秒连接超时 -o /dev/null: 屏蔽原有输出信息 -s: silent -w %{http_code}: 控制额外输出
code=`curl -s -o /dev/null -m 10 --connect-timeout 10 $webUrl -w %{http_code}`
# -ne: 不等于
if [[ $code -ne 200 ]]; then
echo "[error]页面访问失败,code=$code,重启"`date +'%Y-%m-%d %H:%M:%S'`
kill -9 $pid
nohup java -jar -Duser.timezone=GMT+8 $jarUrl/$jarName >> $jarUrl/$logName 2>&1 &
else
echo "[info]页面访问成功,code=$code,time="`date +'%Y-%m-%d %H:%M:%S'`
fi
fi
}
MonitorFunction

注:webUrl应该给出公开访问的地址(比如有登录页面的,应该出登录页的地址而不是首页的地址),不然curl测出来的状态码是302,导致项目没有挂掉也不断地重启。

可以使用如下命令获取目标网址的重定向目标:

1
$curl -Ls -w %{url_effective} -o /dev/null https://google.com    // 把url换成你的目标网址,输出的即可作为webUrl

然后给脚本设置可执行权限,再执行crontab -e命令,设置定时任务。

1
*/1 * * * * bash /myshell/monitor.sh >> /myproject/monitor.log

说明:每一分钟执行一次并将日志打印在固定文件中,若文件不存在会自动创建。

2.3.2 jar包运维脚本

可以把springboot项目打包出的jar包通过运维脚本来管理,新建一个restart.sh的脚本,内容如下:

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
71
72
73
74
75
#!/bin/bash
#这里可替换为你自己的执行程序,其他代码无需更改
APP_NAME=xxl-job-admin-2.1.6.RELEASE.jar

#使用说明,用来提示输入参数
usage() {
echo "Usage: sh 执行脚本.sh [start|stop|restart|status]"
exit 1
}

#检查程序是否在运行
is_exist(){
pid=`ps -ef|grep $APP_NAME|grep -v grep|awk '{print $2}' `
#如果不存在返回1,存在返回0
if [ -z "${pid}" ]; then
return 1
else
return 0
fi
}

#启动方法
start(){
is_exist
if [ $? -eq "0" ]; then
echo "${APP_NAME} is already running. pid=${pid} ."
else
nohup java -jar $APP_NAME > /dev/null 2>&1 &
fi
}

#停止方法
stop(){
is_exist
if [ $? -eq "0" ]; then
kill -9 $pid
else
echo "${APP_NAME} is not running"
fi
}

#输出运行状态
status(){
is_exist
if [ $? -eq "0" ]; then
echo "${APP_NAME} is running. Pid is ${pid}"
else
echo "${APP_NAME} is NOT running."
fi
}

#重启
restart(){
stop
start
}

#根据输入参数,选择执行对应方法,不输入则执行使用说明
case "$1" in
"start")
start
;;
"stop")
stop
;;
"status")
status
;;
"restart")
restart
;;
*)
usage
;;
esac

使用方法:给脚本赋予可执行权限,放到jar同一目录下,执行下列命令管理即可。

1
2
3
4
$ ./restart.sh status
$ ./restart.sh start
$ ./restart.sh stop
$ ./restart.sh restart

3. 科学上网环境的搭建

以下采用一键脚本搭建科学上网环境,虽然足够方便,一般也没有什么问题,但存在一定的隐患,建议运行前先看一下脚本的内容,了解清楚它都对你的服务器做了什么,再去执行。

3.1 SSR服务器端搭建

3.1.1 ShadowsocksR简介

ShadowsocksR是一个高性能安全的socks5代理,基于和兼容Shadowsocks,帮助用户更加安全访问全球网络。ShadowsocksR简称为SSR,支持复杂协议和混淆,有更强的抗干扰能力。

3.1.2 一键脚本搭建SSR服务

1
$ wget -N --no-check-certificate https://makeai.cn/bash/ssrmu.sh && chmod +x ssrmu.sh && bash ssrmu.sh

ssr-server

3.2 Trojan-Go服务器端搭建

3.2.1 Trojan-Go简介

Trojan是一款新型的代理工具,其特点是代理流量和伪装网站共用服务器的443端口,使代理流量被识别为正常的网站浏览,从而降低被封锁的机率。Trojan-Go则是在Trojan的基础上,经过二次开发,优化了原版的一些功能,额外添加了新的功能,比如Trojan-Go支持多路复用,支持CDN流量中转。

3.2.2 一键脚本搭建Trojan-Go服务

1
$ bash <(curl -sL https://raw.githubusercontent.com/phlinhng/v2ray-tcp-tls-web/master/install.sh) && v2script

trojan-go-server

4. 版本控制环境搭建

4.1 Git环境搭建

4.1.1 安装配置Git

Step1:下载安装Git服务器

1
$ apt-get install git

Step2:验证是否安装成功

1
$ git --version

若显示版本信息则说明安装成功。

4.1.2 创建用户并赋予权限

Step1:创建git用户

1
$ adduser git

用户名以git为例,根据提示设置密码。

Step2:赋予git用户权限

1
2
$ chmod 740 /etc/sudoers
$ nano /etc/sudoers

root ALL=(ALL:ALL) ALL这一行下面添加git ALL=(ALL:ALL) ALL

1
2
3
# User privilege specification
root ALL=(ALL:ALL) ALL
git ALL=(ALL:ALL) ALL

保存退出后,修改回文件权限

1
$ chmod 440 /etc/sudoers

Step3:关闭git用户的shell权限

考虑到安全因素,需要禁止git用户ssh登录服务器,设置后git用户可以通过ssh正常使用git服务,但无法登录shell。

1
$ nano /etc/passwd

将最后一行的bash处改为git-shell

1
git:x:1001:1001:,,,:/home/git:/bin/bash 改成 git:x:1001:1001:,,,:/home/git:/bin/git-shell

4.1.3 初始化git仓库并配置SSH

Step1:初始化git仓库

1
2
3
4
$ cd /home/git                    //切换到git用户目录
$ mkdir repo.git //创建仓库目录,以repo.git为例
$ cd repo.git //进入仓库目录
$ git init --bare //使用--bare参数初始化为裸仓库,这样创建的仓库不包含工作区

Step2:查看公钥

打开本地的 git bash,输入以下命令查看公钥(前提是本地已经配好了git环境并完成初始化),复制公钥

1
$ cat ~/.ssh/id_rsa.pub

Step3:配置SSH

1
2
3
4
$ cd /home/git                   //切换到git用户目录
$ mkdir .ssh //创建.ssh目录
$ cd .ssh //进入.ssh目录
$ nano authorized_keys //将本地的公钥复制到authorized_keys文件里

Step4:用户组管理

修改/home/git/repo.git目录的用户组权限为git:git

1
$ sudo chown git:git -R /home/git/repo.git

修改后执行下列命令后再查看

1
$ ls -l /home/git

4.1.4 本地连接远程仓库

打开本地的git bash,检出仓库并设置记住用户名和密码,然后我们就可以使用git进行版本控制了,git无需手动设置开机自启。

Step1:本地检出仓库

1
$ git clone ssh://[email protected]:port/home/git/repo.git

Step2:设置记住用户名和密码

1
$ git config --global credential.helper store

4.2 SVN环境搭建

4.2.1 安装配置SVN

Step1:下载安装SVN服务器

1
$ apt-get install subversion

Step2:创建仓库,首先创建SVN的根目录 svn,然后再创建一个项目目录(以test为例)

1
2
$ mkdir /svn
$ mkdir /svn/test

Step3:创建新的 svn 仓库

1
$ svnadmin create /svn/test

Step4:启动 svn 服务,并指定 svn 数据存储的根目录

1
$ svnserve -d -r /svn

Step5:放行 svn 所使用的3690端口

宝塔面板——安全——放行3690端口(不放行会报错“由于连接方在一段时间后没有正确答复或连接的主机没有反应,连接尝试失败”)

然后就可以用 TortoiseSVN 客户端,在Windows上 Checkout 这个项目了,SVN地址为svn://IP/test

4.2.2 SVN权限控制

默认的SVN配置是允许匿名访问的,我们可以配置权限使其只能通过用户名密码登录后才能访问。

Step1:编辑配置文件

1
$ nano /svn/test/conf/svnserve.conf

添加以下四行代码(或者把原有配置里对应这四项的#及空格去掉,改成如下配置)

1
2
3
4
anon-access = none      
auth-access = write
password-db = passwd
authz-db = authz

这四行的含义分别是:匿名用户无权限、授权用户可写、使用哪个文件作为账号文件、使用哪个文件作为权限文件。

Step2:添加用户名密码

1
$ nano /svn/test/conf/passwd

在后面添加用户名(以testuser为例)和密码(以testpasswd为例)

1
2
[users]
testuser = testpasswd

Step3:给用户分配权限

1
$ nano /svn/test/conf/authz

在后面添加如下权限

1
2
3
[/]
testuser = rw
*=

注:r代表读权限,w代表写权限(如果多个用户就一行一个)

Step4:重启 svn 服务

1
2
$ killall svnserve    
$ svnserve -d -r /svn

重启 svn 服务之后就可以用设置的用户名密码登录了。

4.2.3 SVN开机自启

我们可以使用crontab的@reboot任务实现SVN的开机自启。

Step1:创建 启动svn 服务的shell脚本并赋予执行权限

1
2
3
4
5
$ mkdir /myshell
$ cd /myshell
$ touch startsvn.sh
$ echo "svnserve -d -r /svn" >> startsvn.sh
$ chmod u+x startsvn.sh

Step2:将shell脚本添加到 crontab 计划任务里

1
$ crontab -e

然后把如下内容写入,重启即可

1
@reboot /myshell/startsvn.sh

5. 部署容器环境搭建

5.1 Docker简介

5.1.1 Docker是什么

是什么:Docker是一个用于开发,交付和运行应用程序的开放平台。可以将应用程序与基础架构分开,从而可以快速交付软件。

作用:将一整套环境打包封装成镜像,无需重复配置环境,解决环境带来的种种问题。Docker容器间是进程隔离的,谁也不会影响谁。

官方文档:Docker官方文档

5.1.2 Docker的架构

Docker 其实指代的是用于开发,部署,运行应用的一个平台。平常中说的 Docker 准确来说是 Docker Engine。Docker Engine 是一个 C/S 架构的应用。其中主要的组件有:

  • Docker Server:长时间运行在后台的程序,就是熟悉的 daemon 进程.
  • Docker Client:命令行接口的客户端。
  • REST API:用于和 daemon 进程的交互。

我们通过给 Docker Client 下发各种指令,然后 Client 通过 Docker daemon 提供的 REST API 接口进行交互,来让 daemon 处理编译,运行,部署容器的繁重工作。 大多数情况下, Docker Client 和 Docker Daemon 运行在同一个系统下,但有时也可以使用 Docker Client 来连接远程的 Docker Daemon 进程,也就是远程的 Server 端。

5.1.3 Docker Compose是什么

Compose 是用于定义和运行多容器 Docker 应用程序的工具。通过 Compose,您可以使用 YML 文件来配置应用程序需要的所有服务。然后,使用一个命令,就可以从 YML 文件配置中创建并启动所有服务。

Compose 使用的三个步骤:

  • 使用 Dockerfile 定义应用程序的环境。
  • 使用 docker-compose.yml 定义构成应用程序的服务,这样它们可以在隔离环境中一起运行。
  • 最后,执行 docker-compose up 命令来启动并运行整个应用程序。

5.1.4 Docker与Docker Compose的区别

Docker是一个供开发和运维人员开发,测试,部署和运行应用的容器平台。这种用linux container部署应用的方式叫容器化。

Docker Compose是一个用于运行和管理多个容器化应用的工具。

我们可以列出下列几项来进行二者对比:

  • docker是自动化构建镜像,并启动镜像。 docker compose是自动化编排容器。

  • docker是基于Dockerfile得到images,启动的时候是一个单独的container。

  • docker-compose是基于docker-compose.yml,通常启动的时候是一个服务,这个服务通常由多个container共同组成,并且端口,配置等由docker-compose定义好。

  • 两者都需要安装,但是要使用docker-compose,必须已经安装docker。

5.1.5 直接安装和Docker安装的区别

下面以MySQL数据库为例,看看直接安装MySQL和使用Docker安装MySQL有什么区别:

  • docker安装快速,效率高;
  • docker隔离性好,可以安装无数个mysql实例,互相不干扰,只要映射主机端口不同即可;
  • 占用资源少,MB级别,而服务器安装GB级别;
  • 启动速度秒级,而服务器安装启动分钟级别;
  • 性能接近原生,而服务器安装较低;
  • 数据备份、迁移,docker更方便强大;
  • 卸载管理更方便和干净,直接删除容器和镜像即可;
  • 稳定性,只要保证docker环境没问题,mysql就没问题。

5.2 Docker环境搭建

5.2.1 卸载原先安装的Docker

1
2
$ dpkg -l | grep docker   # 查询相关软件包
$ sudo apt remove --purge xxx # 把查出来的软件包执行此命令(替换xxx)

5.2.2 安装Docker

方式一(推荐):

1
2
3
4
$ apt-get update -y && apt-get install curl -y  # 安装curl
$ curl https://get.docker.com | sh - # 安装docker
$ sudo systemctl start docker # 启动docker服务
$ docker version # 查看docker版本(客户端要与服务端一致)

方式二(过时了):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ sudo apt-get update
$ sudo apt-get install \
apt-transport-https \
ca-certificates \
curl \
gnupg2 \
software-properties-common
$ curl -fsSL https://download.docker.com/linux/debian/gpg | sudo apt-key add -
$ sudo apt-key fingerprint 0EBFCD88
$ sudo add-apt-repository \
"deb [arch=amd64] https://download.docker.com/linux/debian \
$(lsb_release -cs) \
stable"
$ sudo apt-get update
$ sudo apt-get install docker-ce docker-ce-cli containerd.io
$ sudo systemctl start docker
$ docker version

5.2.3 Docker常用命令

[1] 搜索及拉取docker镜像

1
2
$ docker search [NAME]              # 搜索docker镜像(搜索结果里OFFICIAL为OK的是官方镜像)
$ docker pull [NAME] # 拉取指定docker镜像(NAME是搜索出来的指定镜像名)

[2] 查看docker容器实例和镜像

1
2
3
4
$ docker ps -a                      # 查看所有docker容器实例
$ docker ps # 查看所有正在运行的docker容器实例
$ docker images # 查看所有docker镜像
$ docker images [REPOSITORY] # 查看指定docker镜像(REPOSITORY为镜像名)

[3] 开启停止docker容器实例和镜像

1
2
3
4
5
6
$ docker start [ID/NAMES]             # 开启指定docker容器实例
$ docker stop [ID/NAMES] # 停止指定docker容器实例
$ docker restart [ID/NAMES] # 重启指定docker容器实例
$ docker start `docker ps -a -q` # 批量启动所有的docker容器实例
$ docker stop `docker ps -a -q` # 批量停止所有的docker容器实例
$ docker restart `docker ps -a -q` # 批量重启所有的docker容器实例

[4] 强制删除docker容器实例和镜像

1
2
3
4
$ docker rm -f [ID/NAMES]             # 强制删除指定docker容器实例(删除前需先停止实例)
$ docker rmi -f [ID/NAMES] # 强制删除指定docker镜像(删除前需先停止实例)
$ docker rm -f `docker ps -a -q` # 批量强制删除所有的docker容器实例(删除前需先停止实例)
$ docker rmi -f `docker images -q` # 批量强制删除所有的docker镜像(删除前需先停止实例)

[5] 进入/退出docker容器内部

1
2
$ docker exec -it [CONTAINER ID/NAMES] /bin/bash   # 进入指定docker容器内部
$ exit # 从docker容器内部退出

注:如果遇到OCI runtime exec failed: exec failed问题,则使用如下命令进入

1
$ docker exec -it [CONTAINER ID/NAMES] /bin/sh

[6] 查看docker运行日志

1
2
$ docker logs -f [CONTAINER ID/NAMES] --tail 100    # 查看指定条数的docker运行日志
$ docker logs --since 30m [CONTAINER ID/NAMES] # 查看指定分钟内的docker运行日志

[7] docker容器内部的文件上传和下载

1
2
$ docker cp /root/test.txt [CONTAINER ID/NAMES]:/root       # 上传文件
$ docker cp [CONTAINER ID/NAMES]:/root/test.txt /root # 下载文件

[8] Docker空间清理

1
2
$ docker system df                 # 类似于Linux上的df命令,用于查看Docker的磁盘使用情况
$ docker system prune # 可用于清理磁盘,删除关闭的容器、无用的数据卷和网络,以及无tag的镜像)

5.2.4 Docker异常情况

[1] 报错:Cannot kill container <<container id>>: unknown error after kill: runc did not terminate sucessfully: container_linux.go:392: signaling init process caused “permission denied”

解决方法:

Step1:先执行如下命令找到对应的PID

1
$ ps aux | grep <<container id>> | awk '{print $1 $2}'

输出包含:

1
<<user>><<process id>>

Step2:将查出来的PID kill掉

1
$ kill -9 <<process id from above command>>

出现原因:docker version查看后发现是因为client和server版本不一致导致的(上述解决办法只是临时解决,需要把版本统一起来)

[2] 报错:Error response from daemon: Cannot restart container es: OCI runtime create failed: container with id exists: <<container id>>: unknown

解决办法:

1
2
$ find / -name "<<container id>>"
$ rm -rf /run/snap.docker/runtime-runc/moby/<<container id>> // 把查出来的这个文件删掉即可

出现原因:docker version查看后发现是因为client和server版本不一致导致的(上述解决办法只是临时解决,需要把版本统一起来)

5.3 Docker Compose环境搭建

1
2
3
4
5
6
// 下载安装docker-compose,最新版见:https://github.com/docker/compose/releases
$ sudo curl -L https://github.com/docker/compose/releases/download/1.29.2/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
// 赋予docker-compose执行权限
$ sudo chmod +x /usr/local/bin/docker-compose
// 查看docker-compose版本号,验证是否安装成功
$ docker-compose --version

docker compose

5.4 通过Dockerfile自动构建镜像

Step1:在项目里面再新建一个Dockerfile文件(有的开源项目会提供现成的 Dockerfile,如果没有就要自己去写)

Dockerfile语法

Step2:切换到项目目录里,执行如下命令即可成功构建镜像。

1
$ docker build -t 'test-image' .

Step3:我们可以打包导出镜像,示例如下。

1
$ docker save test-image > test-image.v1.dockerimage  

5.4.1 使用Docker部署Springboot项目

Step1:使用Maven将项目打包成jar包,并编写Dockerfile,示例如下:

1
2
3
4
5
6
7
8
9
10
# 基于java8镜像创建新镜像
FROM java:8
# 作者
MAINTAINER eula
# 将jar包添加到容器中并更名为app.jar
COPY test-project-0.0.1-SNAPSHOT.jar /app.jar
# 放行端口
EXPOSE 8888
# 后台运行jar包
ENTRYPOINT ["nohup","java","-jar","/app.jar","&"]

Step2:将jar包和Dockerfile上传到服务器并制作镜像运行容器

1
2
3
$ cd /root/deploy                                                                // 切换到存放jar包和Dockerfile的目录
$ docker build -t test-springboot-image . // 使用Dockerfile构建镜像
$ docker run -d -p 8080:8080 --name test-springboot test-springboot-image:latest // 通过镜像运行容器

5.4.2 使用Docker部署Flask项目

Step1:导出项目依赖,并编写Dockerfile,示例如下:

1
$ pip freeze > requirements.txt

注:建议对项目单独建一个conda虚拟环境,再导出依赖,这样导出的依赖就这一个项目的,就不用手动删除无用的了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 基于python3.7镜像创建新镜像
FROM python:3.7
# 创建容器内部目录
RUN mkdir /code
# 将项目复制到内部目录
ADD test-project /code/
# 切换到工作目录
WORKDIR /code
# 安装项目依赖
RUN pip install -r requirements.txt
# 放行端口
EXPOSE 5000
# 启动项目
ENTRYPOINT ["nohup","python","server.py","&"]

Step2:将项目和Dockerfile上传到服务器并制作镜像运行容器

1
2
3
$ cd /root/deploy                                                       // 切换到存放项目和Dockerfile的目录
$ docker build -t test-flask-image . // 使用Dockerfile构建镜像
$ docker run -d -p 5000:5000 --name test-flask test-flask-image:latest // 通过镜像运行容器

5.5 将已有容器部署到其他服务器

步骤简述:将容器保存成镜像——将镜像打成tar包,压缩成tar.gz——使用scp命令将文件传输到目标服务器——将tar.gz解压成tar包,载入镜像——docker run 运行镜像创建容器

注:通过容器打Docker镜像要比Dockerfile生成的包要大(里面有很多没用的东西),尽量使用后者,但一些需要离线部署并且需要自动下载算法模型的除外。

Step1:将容器保存成镜像

1
2
3
$ docker ps -a
$ docker commit -a "eula" -m "commit uptime-kuma" 1c786853ea40 eula/uptime-kuma:v1.0
$ docker images

说明:-a后面的是提交用户的用户名,-m后面的是提交信息,1c786853ea40是容器id,最后是镜像名及tag,打包出来的镜像如下:

1
2
REPOSITORY                                          TAG            IMAGE ID       CREATED              SIZE
eula/uptime-kuma v1.0 b217262a8fe7 About a minute ago 323MB

Step2:将镜像打包并压缩

1
2
3
$ docker save -o eula-uptime-kuma-v1.0.tar eula/uptime-kuma:v1.0
$ tar -zcvf eula-uptime-kuma-v1.0.tar.gz eula-uptime-kuma-v1.0.tar
$ rm -f eula-uptime-kuma-v1.0.tar

Step3:将文件传输到目标服务器

1
$ scp  -P port /root/eula-uptime-kuma-v1.0.tar.gz [email protected]:/root/eula-uptime-kuma-v1.0.tar.gz

Step4:解压并载入镜像

1
2
3
4
$ tar -zxvf eula-uptime-kuma-v1.0.tar.gz
$ docker load -i eula-uptime-kuma-v1.0.tar
$ docker images
$ rm -f eula-uptime-kuma-v1.0.tar

载入出来的镜像如下:

1
2
REPOSITORY                                      TAG             IMAGE ID        CREATED               SIZE
eula/uptime-kuma v1.0 b217262a8fe7 About an hour ago 323MB

Step5:运行镜像创建容器

1
2
$ docker run -d --restart=always -p 3001:3001 --name uptime-kuma eula/uptime-kuma:v1.0
$ docker ps

6. 项目运行环境搭建

6.1 Docker-MySQL环境搭建

6.1.1 搜索MySQL镜像

1
$ docker search mysql

docker-mysql

通常选择OFFICIAL里Star数最多的那个镜像,即mysql。

6.1.2 拉取MySQL镜像

1
$ docker pull mysql:5.7

6.1.3 创建实例容器并运行

1
2
3
4
5
6
7
$ docker run -p 3306:3306 --name mysql \
-e TZ=Asia/Shanghai \
-v /mydocker/mysql/conf:/etc/mysql/conf.d \
-v /mydocker/mysql/logs:/var/log/mysql \
-v /mydocker/mysql/data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=[password] \
-d mysql:5.7 --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci

命令解释说明:

1
2
3
4
5
6
7
-p 3306:3306:将主机的3306端口映射到docker容器的3306端口。
--name mysql:运行服务名字
-e TZ=Asia/Shanghai:时区是使用了世界标准时间(UTC)。因为在中国使用,所以需要把时区改成东八区的。
-e MYSQL_ROOT_PASSWORD=[password]:初始化 root 用户的密码。
-d mysql:5.7 : 后台程序运行mysql5.7
--character-set-server=utf8mb4 :设置字符集
--collation-server=utf8mb4_unicode_ci:设置校对集

设置开机自启

1
$ docker update mysql --restart=always

6.1.4 创建数据库及用户

在本地使用Navicat工具使用root用户连接上该数据库(国外服务器建议配置代理),使用如下四条命令创建数据库及用户。

1
2
3
4
5
6
7
8
9
10
11
--创建新的数据库,并设置数据库编码
$ CREATE DATABASE 你的数据库名 DEFAULT CHARSET=utf8 DEFAULT COLLATE utf8_unicode_ci;

--创建新的用户
$ CREATE USER '你的用户名'@'你的服务器IP' IDENTIFIED BY '你的密码';

--把数据库的管理权限给予刚刚创建的MySQL用户
$ GRANT ALL PRIVILEGES ON *.* TO '你的用户名'@'%';

--刷新权限,使用设置生效
$ FLUSH PRIVILEGES;

注:如果连接数据库时出现Access denied for user '用户名'@'某IP' (using password: YES)问题,则是第三句授权出了问题,你的本地外网IP被拦截了,那个’%’代表的是访问IP不受限制。

6.1.5 数据库的备份与恢复

[1] 数据备份

可以使用mysqldump实现,docker-mysql的数据库备份语句如下:

1
2
3
4
5
6
7
8
9
10
11
// 备份单个数据库的结构与数据
$ docker exec mysql sh -c "exec mysqldump --databases 数据库名 -u root -p'root密码'" > /mydocker/mysql/backup/db.sql

// 备份单个数据库的结构
$ docker exec mysql sh -c "exec mysqldump --databases 数据库名 -d -u root -p'root密码'" > /mydocker/mysql/backup/db.sql

// 备份所有数据库的结构与数据
$ docker exec mysql sh -c "exec mysqldump --databases --all-databases -u root -p'root密码'" > /mydocker/mysql/backup/db.sql

// 备份所有数据库的结构
$ docker exec mysql sh -c "exec mysqldump --databases --all-databases -d -u root -p'root密码'" > /mydocker/mysql/backup/db.sql

说明:1)如果安的是原生mysql,直接执行mysqldump语句备份即可。2)如果需要同时导出多个数据库,“数据库名”处用空格分割多个数据库即可。3)不要数据只保留数据库结构的话加个-d参数即可。

[2] 数据恢复

docker-mysql的数据库恢复语句如下:

1
docker exec -i mysql sh -c "exec mysql -uroot -p'root密码'" < /mydocker/mysql/backup/db.sql

注:建议使用命令去恢复数据,直接用Navicat工具运行导出的sql来恢复数据有时会出问题(比如我就遇到过导出的库在Navicat执行报错,但用命令可以导入成功的情况)

6.1.6 数据库的定时备份

实际在生产环境上,我们不会每天都去手动备份。可以写一个脚本出来,完成这项操作,然后用 crontab 定时执行。

Step1:新建一个mysqlbackup.sh脚本,并使用chmod u+x命令赋予可执行权限,脚本内容如下:

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
#!/bin/bash
#数据库用户名
dbuser='root'
#数据库密码
dbpasswd='root密码'
#数据库名,如有多个库用空格分开
dbname='dbname1 dbname2 dbname3'
#备份时间
backuptime=`date +"%Y-%m-%d"`
#备份输出目录
path='/mydocker/mysql/backup'
#备份输出日志
log='mysqlbackup.log'

echo "################## ${backuptime} #############################"
echo "开始备份"
#日志记录头部
echo "" >> ${path}/${log}
echo "-------------------------------------------------" >> ${path}/${log}
echo "备份时间为${backuptime},备份数据库 ${dbname} 开始" >> ${path}/${log}
#正式备份数据库
for table in ${dbname}; do
docker exec mysql sh -c "exec mysqldump --databases ${table} -u ${dbuser} -p'${dbpasswd}'" > ${path}/${table}-${backuptime}.sql 2>> ${path}/${log};
#备份成功以下操作
if [ "$?" == 0 ];then
cd ${path}
#为节约硬盘空间,将数据库压缩
tar Jcvf ${table}-${backuptime}.tar.gz ${table}-${backuptime}.sql > /dev/null
#删除原始文件,只留压缩后文件
rm -f ${path}/${table}-${backuptime}.sql
#删除30天前备份
find ${path} -name "*.tar.gz" -type f -mtime +30 -exec rm -rf {} \; > /dev/null 2>&1
echo "数据库表 ${table} 备份成功!!" >> ${path}/${log}
else
#备份失败则进行以下操作
echo "数据库表 ${table} 备份失败!!" >> ${path}/${log}
fi
done
echo "完成备份"
echo "备份日志见 ${path}/${log} "
echo "################## ${backuptime} #############################"

说明:

1)上面的信息部分换成自己的,备份输出目录的末尾不要加‘/’,多个数据库用空格分隔不要加逗号。

2)正式备份数据库的语句也换成自己的,注意"exec mysqldump --databases ${table} -u ${dbuser} -p'${dbpasswd}'"处外面是双引号,里面套单引号,反过来会因为${}导致转义问题。

3)为了节约硬盘空间,我这里对sql进行了压缩(如果不想压缩就不用安了,注释掉相关代码即可),请先安装xz命令。

1
$ apt-get install xz-utils

4)为了节约硬盘空间,我这里删除了30天前的备份(根据文件的最后改动时间来判定),具体保留几天自己定就行。

Step2:配置定时任务执行脚本

1
$ crontab -e

然后添加如下代码保存即可:

1
59 23 * * * 脚本路径/mysqlbackup.sh

说明:含义是每天23:59分自动执行脚本,详细使用见上文”2.2.6 Crontab定时任务”.

6.2 Docker-Nginx环境搭建

6.2.1 获取Nginx镜像

1
2
$ docker search nginx 
$ docker pull nginx

6.2.2 创建Nginx容器

Step1:查看我们拉取到本地的nginx镜像IMAGE ID

1
$ docker images nginx

Step2:创建并启动容器

1
$ docker run -d --name nginx -p 9999:80 [image-id]

命令解释说明:

1
2
3
4
- -d  指定容器以守护进程方式在后台运行
- --name 指定容器名称,此处我指定的是nginx
- -p 指定主机与容器内部的端口号映射关系,格式 -p [宿主机端口号]:[容器内部端口],此处我使用了主机9999端口,映射容器80端口
- 最后 是nginx的镜像IMAGE ID(可以省略后面的部分,能唯一区分即可)

6.2.3 修改Nginx配置文件

[1] 每次都进入到nginx容器内部修改–适用于临时修改情况

Step1:进入到nginx容器内部

1
docker exec -it [CONTAINER ID/NAMES] /bin/bash

命令解释说明:

1
2
3
4
- exec 命令代表附着到运行着的容器内部
- -it 是 -i 与 -t两个参数合并写法,-i -t 标志着为我们指定的容器创建了TTY并捕捉了STDIN
- [CONTAINER ID/NAMES] 是我们要进入的容器ID(可以省略后面的部分,能唯一区分即可)或名字
- /bin/bash 指定了执行命令的shell

进入到nginx容器内部后,我们可以cd /etc/nginx,可以看到相关的nginx配置文件都在/etc/nginx目录下。而nginx容器内的默认首页html文件目录为/usr/share/nginx/html,日志文件位于/var/log/nginx。执行exit命令可以从容器内部退出。

[2] 将nginx容器内部配置文件挂载到主机–适用于频繁修改情况

Step1:创建挂载目录

这里我为了跟mysql的挂载目录保持一致,也使用了自己创建的/mydocker目录(一般放在/mnt目录,这个是Linux专门的挂载目录)

1
2
$ cd /mydocker
$ mkdir -p ./nginx/{conf,html,logs}

Step2:将容器内的nginx.confdefault.conf文件分别拷贝到主机/mydocker/nginx/mydocker/nginx/conf目录下

1
2
3
$ cd /mydocker/nginx
$ docker cp [CONTAINER ID/NAMES]:/etc/nginx/nginx.conf ./
$ docker cp [CONTAINER ID/NAMES]:/etc/nginx/conf.d/default.conf ./conf/

命令解释说明:

1
2
- [CONTAINER ID/NAMES] 是我们要进入的容器ID(可以省略后面的部分,能唯一区分即可)或名字
- /etc/nginx/nginx.conf 是容器内部nginx.conf的路径

Step3:重新创建容器实例

先停止、删除原有的容器实例

1
2
$ docker stop [CONTAINER ID/NAMES]              # 停止指定docker容器实例
$ docker rm -f [CONTAINER ID/NAMES] # 强制删除指定docker容器实例(删除前需先停止实例)

再重新创建新的容器实例

1
$ docker run -d --name nginx -p 9999:80 -v /mydocker/nginx/nginx.conf:/etc/nginx/nginx.conf -v /mydocker/nginx/logs:/var/log/nginx -v /mydocker/nginx/html:/usr/share/nginx/html -v /mydocker/nginx/conf:/etc/nginx/conf.d --privileged=true [image-id]

命令解释说明:

1
2
-v 挂载目录,表示将主机目录与容器目录之间进行共享
--privileged=true 容器内部对挂载的目录拥有读写等特权

Step4:设置开机自启

1
$ docker update nginx --restart=always

6.2.4 测试Nginx环境

Step1:新建测试用的index.html文件(不配置会出现403报错)

1
2
3
$ cd /mydocker/nginx/html
$ touch index.html
$ echo "hello world" >> index.html

Step2:打开Chrome浏览器,地址输入IP:port,出现hello world即配置成功。

6.2.5 搭建过程踩的坑

情景描述:搭建完的nginx在本地用curl IP:port可以访问(当然在nginx容器里使用curl 127.0.0.1也是可以访问的),但在Chrome浏览器内找不到该地址(提示“该网页可能已永久移到新的网址”)

错误原因:创建nginx容器时误用了Chrome浏览器的默认非安全端口,访问会直接被拦截,因而出现了该情况。Chrome 默认非安全端口列表如下:

1
1, 7, 9, 11, 13, 15, 17, 19, 20, 21, 22, 23, 25, 37, 42, 43, 53, 77, 79, 87, 95, 101, 102, 103, 104, 109, 110, 111, 113, 115, 117, 119, 123, 135, 139, 143, 179, 389, 465, 512, 513, 514, 515, 526, 530, 531, 532, 540, 556, 563, 587, 601, 636, 993, 995, 2049, 3659, 4045, 6000, 6665, 6666, 6667, 6668, 6669

解决办法:删掉nginx容器重新搭建,创建nginx容器时避开Chrome浏览器的默认非安全端口即可。

6.2.6 Nginx的一些其他管理命令

1
2
$ nginx -s reload           # 重新加载配置文件,而nginx服务不会中断
$ nginx -t # 检查nginx配置的语法是否正确

6.3 Docker-Redis环境搭建

6.3.1 获取Redis镜像

1
$ docker pull redis:3.2.8

6.3.2 创建Redis容器

1
2
$ docker run --name redis -p 6379:6379 -d redis:3.2.8 --requirepass "mypassword"
$ docker update redis --restart=always

6.3.3 Redis数据库的可视化连接

建议使用 AnotherRedisDesktopManager 开源工具。

6.4 Docker-Oracle环境搭建

6.4.1 拉取镜像并运行容器

1
2
3
$ docker pull registry.cn-hangzhou.aliyuncs.com/helowin/oracle_11g 
$ docker run -d -p 1521:1521 --name oracle11g registry.cn-hangzhou.aliyuncs.com/helowin/oracle_11g
$ docker update oracle11g --restart=always

6.4.2 进入容器进行配置

Step1:进入容器,切换到root用户

1
2
$ docker exec -it oracle11g /bin/bash  # 进入oracle11g容器
$ su root # 默认密码:helowin (可通过passwd命令修改成自己的)

Step2:配置环境变量

1
$ vi /etc/profile

在末尾加上:

1
2
3
export ORACLE_HOME=/home/oracle/app/oracle/product/11.2.0/dbhome_2
export ORACLE_SID=helowin
export PATH=$ORACLEHOME/bin:PATH

Step3:创建软连接,并用oracle用户登录

1
2
$ ln -s $ORACLE_HOME/bin/sqlplus /usr/bin   # 创建软链接
$ su - oracle # 切换到oracle用户

6.4.3 修改密码创建用户

1
2
3
4
5
6
7
$ sqlplus /nolog  #
$ conn / as sysdba # 以dba身份登录

# 修改用户system、sys用户的密码
$ alter user system identified by system;
$ alter user sys identified by sys;
$ ALTER PROFILE DEFAULT LIMIT PASSWORD_LIFE_TIME UNLIMITED;

6.4.4 用连接工具登录

在PLSQL里使用 system/system 账号连接,注意服务名不是orcl,而是helowin。

具体可查看tnsnames.ora文件的配置:

1
$ vi /home/oracle/app/oracle/product/11.2.0/dbhome_2/network/admin/tnsnames.ora

6.5 Docker-ElasticSearch环境搭建

6.5.1 拉取镜像并运行容器

1
2
3
4
5
6
7
$ docker pull elasticsearch:7.14.1
$ docker run -d \
--name es \
-p 9200:9200 -p 9300:9300 \
-e "discovery.type=single-node" -e ES_JAVA_OPTS="-Xms200m -Xmx200m" \
elasticsearch:7.14.1
$ docker update es --restart=always

6.5.2 进入容器进行配置

这时使用docker ps命令查看虽然运行起来了,但还无法访问,需要进入容器内部修改配置解决跨域问题。

1
2
3
4
5
$ docker ps
$ docker exec -it es /bin/bash
$ cd config
$ chmod o+w elasticsearch.yml
$ vi elasticsearch.yml

其中,在 elasticsearch.yml 文件的末尾添加以下三行代码(前两行解决跨域问题,第三行开启xpack安全认证)

1
2
3
http.cors.enabled: true
http.cors.allow-origin: "*"
xpack.security.enabled: true

然后把权限修改回来,重启容器,设置账号密码,浏览器访问http://IP:9200地址即可(用 elastic账号 和自己设置的密码登录即可)

1
2
3
4
5
$ chmod o-w elasticsearch.yml
$ exit
$ docker restart es
$ docker exec -it es /bin/bash
$ ./bin/elasticsearch-setup-passwords interactive // 然后设置一大堆账号密码

注:可借助 ElasticSearch Head Chrome插件实现ES数据库的可视化管理。

6.5.3 ES的导入与导出

ES需要插件才能进行数据的导出和导入,进行备份和恢复操作,这里推荐使用 elasticdump

Step1:安装npm

1
2
$ sudo apt update
$ sudo apt install nodejs npm

Step2:安装elasticdump插件

1
$ npm install elasticdump -g

ES的导入导出(以导出为例):

1
2
3
4
$ elasticdump \
--input=http://username:[email protected]:port/index \
--output=/data/index.json \
--type=data

说明:开启了xpack安全认证的话就要像上面那样加上username:[email protected],没有的话就不需要加。导入跟导出命令基本一致,互换一下input和output的内容即可。

6.5.4 ES的定期自动备份

实际在生产环境上,我们不会每天都去手动备份。可以写一个脚本出来,完成这项操作,然后用 crontab 定时执行。

Step1:新建一个esbackup.sh脚本,并使用chmod u+x命令赋予可执行权限,脚本内容如下:

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
#!/bin/bash
#ES路径
address='ip:port'
#ES用户名
user='username'
#ES密码
passwd='password'
#ES索引名
index='index'
#备份时间
backuptime=`date +"%Y-%m-%d"`
#备份输出目录
path='/mydocker/es/backup'
#备份输出日志
log='esbackup.log'

echo "################## ${backuptime} #############################"
echo "开始备份"
#日志记录头部
echo "" >> ${path}/${log}
echo "-------------------------------------------------" >> ${path}/${log}
echo "备份时间为${backuptime},备份索引 ${index} 开始" >> ${path}/${log}
#正式备份数据库
elasticdump \
--input=http://${user}:${passwd}@${address}/${index} \
--output=${path}/${index}-${backuptime}.json \
--type=data 2>> ${path}/${log};
#备份成功以下操作
if [ "$?" == 0 ];then
cd ${path}
#为节约硬盘空间,将数据库压缩
tar Jcvf ${index}-${backuptime}.tar.gz ${index}-${backuptime}.json > /dev/null
#删除原始文件,只留压缩后文件
rm -f ${path}/${index}-${backuptime}.json
#删除30天前备份
find ${path} -name "*.tar.gz" -type f -mtime +30 -exec rm -rf {} \; > /dev/null 2>&1
echo "索引 ${index} 备份成功!!" >> ${path}/${log}
else
#备份失败则进行以下操作
echo "索引 ${index} 备份失败!!" >> ${path}/${log}
fi

echo "完成备份"
echo "备份日志见 ${path}/${log} "
echo "################## ${backuptime} #############################"

说明:

1)上面的信息部分换成自己的,备份输出目录的末尾不要加‘/’,多个数据库用空格分隔不要加逗号。

2)为了节约硬盘空间,我这里对sql进行了压缩(如果不想压缩就不用安了,注释掉相关代码即可),请先安装xz命令。

1
$ apt-get install xz-utils

3)为了节约硬盘空间,我这里删除了30天前的备份(根据文件的最后改动时间来判定),具体保留几天自己定就行。

Step2:配置定时任务执行脚本

1
$ crontab -e

然后添加如下代码保存即可:

1
59 23 * * * 脚本路径/esbackup.sh

说明:含义是每天23:59分自动执行脚本,详细使用见上文”2.2.6 Crontab定时任务”.

6.6 Docker-Neo4j环境搭建

6.6.1 拉取镜像并运行容器

1
2
3
$ docker pull neo4j
$ docker run -d --name neo4j -p 7474:7474 -p 7687:7687 -v /mydocker/neo4j/data:/data -v /mydocker/neo4j/logs:/logs -v /mydocker/neo4j/conf:/var/lib/neo4j/conf -v /mydocker/neo4j/import:/var/lib/neo4j/import --env NEO4J_AUTH=neo4j/neo4jpassword neo4j
$ docker update neo4j --restart=always

6.6.2 neo4j的可视化查看

浏览器打开:http://IP:7474/browser/ 查看即可。

7. 网站环境搭建

7.1 申请泛域名SSL证书并开启HTTPS

SSL证书是一种数字证书,用于加密从用户的浏览器发送到Web服务器的数据。 通过这种方式,发送的数据对于使用Wireshark等数据包嗅探器来拦截和窃听您的通信的黑客来说是安全的。

Chrome一直在推动https,所有的http协议网站被标记为不安全,如果再不对网站进行https改造的话,那么可能会对信任度造成一定的影响,所以说对一个面向用户的网站来说,开启https是非常有必要的。

下面将使用acme.sh开源项目申请免费的Let’s Encrypt 泛域名SSL证书。

7.1.1 安装 acme.sh

1
$ curl  https://get.acme.sh | sh

acme.sh

普通用户和 root 用户都可以安装使用,安装过程进行了以下几步:

  • [1] 把 acme.sh 安装到你的 root 目录下,并创建 一个 bash 的 alias, 方便你的使用。

  • [2] 自动为你创建 cronjob, 每天 0:00 点自动检测所有的证书, 如果快过期了, 需要更新, 则会自动更新证书。

注:安装过程不会污染已有的系统任何功能和文件,所有的修改都限制在安装目录中。那个socat未安装的问题不用管,那是http验证无Web Server时才需要的。

7.1.2 生成SSL泛域名证书

acme.sh 实现了 acme 协议支持的所有验证协议,一般有两种方式验证:http 和 dns 验证。

  • http 验证:http 方式需要在你的网站根目录下放置一个文件,来验证你的域名所有权。
  • dns 验证:dns 方式,在域名上添加一条 txt 解析记录,验证域名所有权。

dns 方式的可以使用域名解析商提供的 API 自动添加 txt 记录完成验证,下面我们将采用这种方法申请Namesilo的泛域名证书。

Step1:打开 https://www.namesilo.com/account/api-manager 去申请 NameSilo API,勾选第2个复选框,点击Generate,即可生成。

申请NameSilo API

注:务必不要勾选上Generate key for read-only access的哪个复选框,否则会导致Unable to add the DNS record. Error add txt for domain的问题。另外,生成的API只出现一次,如果没记下来只能重置。

Step2:在服务器输入以下命令,实现自动dns验证生成泛域名证书。

1
2
3
$ cd /root/.acme.sh
$ export Namesilo_Key="xxxxxxxxxxxxxxxxxxxxxxxx"
$ ./acme.sh --issue --dns dns_namesilo --dnssleep 1800 -d example.com -d *.example.com

等待1800s即可看到申请下来的SSL证书(NameSilo的验证比较慢,官方文档上写的900s有时不足以验证完)

申请下来的SSL证书

生成文件都放在/root/.acme.sh/example.com/目录下,其中:example.com.key是密钥文件,fullchain.cer是证书文件。

注:如果你的域名不是NameSilo的,上述操作有所不同,具体请参考: https://github.com/acmesh-official/acme.sh/wiki/dnsapi

7.1.3 acme.sh的一些其他管理命令

[1] 更新 acme.sh

目前由于 acme 协议和 letsencrypt CA 都在频繁的更新, 因此 acme.sh 也经常更新以保持同步。

1
2
3
4
$ ./acme.sh --upgrade                          # 升级 acme.sh 到最新版
$ ./acme.sh --upgrade --auto-upgrade # 开启自动升级
$ ./acme.sh --upgrade --auto-upgrade 0 # 关闭自动更新
$ ./acme.sh --uninstall # 卸载acme.sh

[2] 管理证书

1
2
$ ./acme.sh --list                              # 查看证书列表
$ ./acme.sh remove example.com # 删除指定证书

注:证书/密钥文件未从磁盘中删除,需要自己去删除相应的目录/root/.acme.sh/example.com/

[3] 证书自动续订

安装了 acme.sh 后,它会添加一个自动任务到你服务器的Cron里,每天都会检查你的证书是否快要过期,acme.sh 会自动帮你续签。

1
2
$ ./acme.sh --renew -d example.com --force      # 强制续签证书
$ ./acme.sh --remove -d example.com [--ecc] # 停止续签证书

[4] 错误排查

如果使用命令出现了错误,可在原有命令的基础上加上--debug排查问题。

7.1.4 给网站开启HTTPS

打开宝塔面板——网站——设置——SSL——其他证书,把example.com.key密钥文件、fullchain.cer证书文件复制上去,强制https。

开启HTTPS

7.2 网站开启CDN服务

7.2.1 CDN与Cloudflare是什么

CDN的全称是Content Delivery Network,即内容分发网络。 CDN是构建在现有网络基础之上的智能虚拟网络,依靠部署在各地的边缘服务器,通过中心平台的负载均衡、内容分发、调度等功能模块,使用户就近获取所需内容,降低网络拥塞,提高用户访问响应速度和命中率。 CDN的关键技术主要有内容存储和分发技术。

Cloudflare 是一家全球最著名的 CDN 加速服务商,提供了免费和付费的网站加速和保护服务。即使是免费版,也提供了比较全面和强大的功能,非常不错。对于国外访问(或者使用代理)的加速效果十分明显,但对国内访问加速效果十分有限,如果是国内商用的话还是要买国内的CDN服务。

Cloudflare CDN

通过使用 Cloudflare CDN 服务提供的全球节点,一方面可以提高网站响应速度和性能,节省源站资源;另一方面也可以保护站点抵御攻击,保证网站长期稳定在线。

7.2.2 开启 Cloudflare CDN 服务

Step1:打开 Cloudflare CDN官网 注册账号,登录后点击添加站点(填根域名即可),选择选择 Free 套餐,确认计划。

Step2:这时 Cloudflare 会自动扫描域名已有的 DNS 解析记录,如果扫描到的话,会显示在下面,没有或者显示不正确,则需要我们自己设置。

开启Cloudflare CDN

Step3:添加成功后会显示在下面,点击 Continue 继续,按说明修改自己的域名服务器为 Cloudflare 给出的地址。

修改域名服务器地址

NameSilo的修改方式是:勾选域名——点击Change Nameservers——删掉原有的名称服务器,添加新的域名服务器。

NameSilo修改域名服务器

注:修改域名服务器后需要一定时间生效,不会立即检测到,需要稍微等待一会儿(可打开cmd输入nslookup 域名进行验证,如有多个IP出现,则证明已生效)。配置了CDN之后再ping域名指向的就不是我们服务器本身的IP地址了,这样对保护我们的服务器也有好处。

Step4:CDN生效后主页的域名处会标注绿色的“有效“二字,这时我们就可以开启CDN的各种服务了,根据自己需求进行配置就好。

Cloudflare CDN功能

7.2.3 CDN缓存问题

开启了CDN之后,网站的一些静态资源在更新后不会即时刷新,需要等待一段时间。如果你是在调试过程,想要即时看到结果,可以开启开发模式(登录Cloudflare CDN——缓存——配置——打开“开发模式”的按钮)

Cloudflare CDN的开发模式

7.3 Git Hooks自动部署

7.3.1 Git Hooks简介

Git 除了用作版本控制,还有许多高级功能,Git Hooks 就是其中之一。简单来说,Hook 就是在执行某个事件之前或之后进行一些其他额外的操作。Git 支持的非常多的钩子供我们使用,下面以post-receive钩子为例讲解自动部署项目。

在本地修改项目并生成编译后用于部署的文件,使用Git推送到VPS的Git仓库。Git Hooks实际上就是当Git仓库收到最新的push时,将Git仓库接受到的内容复制到VPS上的网站目录内。相当于完成了手动将用于部署的文件复制到VPS网站根目录里的操作。

7.3.2 新建网站

Step1:宝塔面板安装Nginx环境(软件商店——搜索安装Nginx)

Step2:网站——添加站点——填写域名(不创建FTP、数据库、PHP)后提交即可

Step3:修改网站根目录的用户组权限为git:git

1
$ sudo chown git:git -R 网站根目录

修改后执行下列命令后再查看

1
$ ls -l 网站根目录

7.3.3 修改Nginx配置

网站——指定站点——设置——配置文件

在宝塔默认的配置文件里注释掉以下代码

1
2
3
4
5
6
7
8
9
10
11
12
13
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$
{
expires 30d;
error_log /dev/null;
access_log /dev/null;
}

location ~ .*\.(js|css)?$
{
expires 12h;
error_log /dev/null;
access_log /dev/null;
}

再添加如下代码(按照自己的网站根目录来,宝塔生成的根目录默认为新建网站时加的域名)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
location ~* ^.+\.(ico|gif|jpg|jpeg|png)$ {
root 网站根目录;
access_log off;
expires 1d;
}

location ~* ^.+\.(css|js|txt|xml|swf|wav)$ {
root 网站根目录;
access_log off;
expires 10m;
}

location / {
root 网站根目录;
if (-f $request_filename) {
rewrite ^/(.*)$ /$1 break;
}
}

location /nginx_status {
stub_status on;
access_log off;
}

7.3.4 配置Git Hooks

创建post-receive文件

1
2
$ cd /home/git/blog.git/hooks     //切换到hooks目录下
$ nano post-receive //创建post-receive文件并编辑

编写post-receive文件(以下仅作为参考,根据实际情况来写)

1
2
3
4
5
6
7
8
#!/bin/bash
GIT_REPO=/home/git/blog.git
TMP_GIT_CLONE=/tmp/blog
PUBLIC_WWW=网站根目录
rm -rf ${TMP_GIT_CLONE}
git clone $GIT_REPO $TMP_GIT_CLONE
rm -rf ${PUBLIC_WWW}/*
cp -rf ${TMP_GIT_CLONE}/* ${PUBLIC_WWW}

保存退出后,赋予其执行权限

1
$ chmod +x post-receive

7.4 给网站设置反向代理

宝塔面板——网站——设置——反向代理——添加反向代理——填写代理名称和目标URL(http://127.0.0.1:port

8. 开发辅助环境搭建

8.1 搭建ReverseProxy破解JRebel热部署插件

JRebel是一款非常好用的Springboot热部署插件,但它是付费的,我们可以通过ReverseProxy服务进行破解。

这个反向代理需要一直开启着,关了就会出现连不上license server的问题,因此不建议在本机搭建,在自己VPS上搭建更为方便使用。

8.1.1 在VPS搭建ReverseProxy服务

Step1:去lanyus大佬的Github下载自己VPS对应的工具:http://github.com/ilanyu/ReverseProxy/releases/tag/v1.4,上传到服务器的/root目录,并将文件权限改为777。

1
2
$ wget https://github.com/ilanyu/ReverseProxy/releases/download/v1.4/ReverseProxy_linux_amd64
$ chmod 777 ReverseProxy_linux_amd64

Step2:输入以下命令运行该代理工具:

1
$ ./ReverseProxy_linux_amd64

参数说明:

1
2
3
4
5
6
7
Usage of ./ReverseProxy_linux_amd64:
-ip string
reverse proxy addr server ip
-l string
listen on ip:port (default "0.0.0.0:8888")
-r string
reverse proxy addr (default "http://idea.lanyus.com:80")

在Jrebel的激活URL处填写:http://{VPS的IP地址}:8888/{GUID}即可成功激活。下面是一些优化部署,建议加上但不强制。

8.1.2 配置开机自启、HTTPS及反向代理

Step1:使用 crontab 计划任务配置开机自启,见本文2.2.5节

Step2:申请SSL泛域名证书并开启HTTPS,见本文7.1节

Step3:宝塔面板新建网站并设置反向代理,见本文7.4节(注:目标URL填写为http://127.0.0.1:8888

Step4:在Jrebel的激活URL处填写:https://domain.com/{GUID}即可成功激活。

8.2 搭建ProxyPool爬虫代理IP池

使用Python爬虫抓取数据的时候,我们经常会触发目标网站的反爬虫措施(通常是封IP,需要输入验证才能继续访问),导致抓取中断。我们可以利用网上的代理IP网站(有免费的也有付费的)去构建代理池,封了就自动换一个IP继续抓取。

ProxyPool是一个爬虫代理IP池的项目,可以自动从代理IP网站抓取可用的代理,目前支持十余个免费代理源,也可以自己添加代理源。

1
2
3
4
5
6
7
8
9
______                        ______             _
| ___ \_ | ___ \ | |
| |_/ / \__ __ __ _ __ _ | |_/ /___ ___ | |
| __/| _// _ \ \ \/ /| | | || __// _ \ / _ \ | |
| | | | | (_) | > < \ |_| || | | (_) | (_) || |___
\_| |_| \___/ /_/\_\ \__ |\_| \___/ \___/ \_____\
__ / /
/___ /

官方提供的测试地址:http://demo.spiderpy.cn (懒得自己搭建的话也可以用这个,下面就不用看了)

8.2.1 搭建Redis数据库

ProxyPool的部署需要用到Redis数据库,用以存储代理IP信息,因此我们首先要搭建Redis数据库。

需要注意的一点是Redis数据库的版本不要太高,我一开始用的最新版报错,降级到3.2.8版本就好了。

Docker-Redis环境的搭建见本文6.3节

8.2.2 使用Docker部署ProxyPool项目

依次执行以下命令,拉取镜像并创建容器。

1
2
3
$ docker pull jhao104/proxy_pool
$ docker run --name proxy_pool --env DB_CONN=redis://:"password"@ip:port/db -p 5010:5010 jhao104/proxy_pool:latest
$ docker update proxy_pool --restart=always

注:第二条命令db处填写的应该是0-15的一个数字,否则会报:redis.exceptions.ResponseError: invalid DB index错误。

可以使用以下命令进入容器内部,配置文件是setting.py,我们可以根据自己的需求进行更改配置。

1
2
$ docker exec -it proxy_pool /bin/sh
$ vi setting.py

注:建议将检测代理IP可用性的网址换成你要爬取的目标网址。

扩展代理也在这个文件里配置,详见项目的README吧,我这里就不赘述了。

8.2.3 配置HTTPS及反向代理

Step1:申请SSL泛域名证书并开启HTTPS,见本文7.1节

Step2:宝塔面板新建网站并设置反向代理,见本文7.4节(注:目标URL填写为http://127.0.0.1:5010

8.2.4 ProxyPool的API服务

用Chrome浏览器打开:https://域名,即可访问API接口服务。

ProxyPool的API

8.2.5 在爬虫中使用ProxyPool

如果要在爬虫代码中使用的话, 可以将此API封装成函数直接使用,以下是官方提供的示例,仅供参考。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import requests

def get_proxy():
return requests.get("http://127.0.0.1:5010/get/").json()

def delete_proxy(proxy):
requests.get("http://127.0.0.1:5010/delete/?proxy={}".format(proxy))

# your spider code

def getHtml():
# ....
retry_count = 5
proxy = get_proxy().get("proxy")
while retry_count > 0:
try:
html = requests.get('http://www.example.com', proxies={"http": "http://{}".format(proxy)})
# 使用代理访问
return html
except Exception:
retry_count -= 1
# 删除代理池中代理
delete_proxy(proxy)
return None

注:由于代理池的节点并不全部有效,我们使用的时候仍然会有出错的情况。我这里提供一个思路——直接获取全部代理,依次尝试,把requests请求放在try-except代码块里,请求的时候检测response的状态码,如果不是200的话就再获取下一个代理节点。如果捕捉到异常或者获取的代理IP数为0,就尝试不使用代理抓取,再失败的话就报错。

建议配合上其他反反爬手段一起使用,比如随机headers、随机sleep等等。总之我用上这些手段之后,基本不被再被反爬了。

8.3 搭建EMQX物联网MQTT消息服务器

EMQX 是一款大规模可弹性伸缩的云原生分布式物联网 MQTT 消息服务器,高效可靠连接海量物联网设备,实时双向移动物联网数据,助力构建关键业务的物联网平台与应用。

8.3.1 使用Docker搭建EMQX消息服务器

1
2
$ docker pull emqx/emqx
$ docker run -d --name emqx -p 1883:1883 -p 8086:8086 -p 8883:8883 -p 8084:8084 -p 18083:18083 emqx/emqx

搭建完后用浏览器访问 http://IP:18083/地址,默认账号及密码为:admin / public

EMQX物联网MQTT消息服务器面板

8.3.2 与之配套的客户端MQTTX

MQTTX是一个跨平台的 MQTT 5.0 桌面客户端工具,与EMQX搭配使用。

下载地址:https://mqttx.app/zh

MQTTX桌面客户端

说明:MQTTX崩溃的问题——删掉 C:\Users\xxx\AppData\Roaming\MQTTX\db.json 即可恢复(但原来的配置信息也都没了)

8.4 Docker可视化工具Portainer的部署

8.4.1 Portainer简介

项目简介:Portainer是Docker的图形化管理工具,提供状态显示面板、应用模板快速部署、容器镜像网络数据卷的基本操作、事件日志显示、容器控制台操作、Swarm集群和服务等集中管理和操作、登录用户管理和控制等功能。功能十分全面,基本能满足中小型单位对容器管理的全部需求。

项目地址:https://github.com/portainer/portainer

8.4.2 Portainer部署

1
2
$ docker pull portainer/portainer
$ docker run -d -p 9000:9000 --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data --name portainer portainer/portainer

用Chrome浏览器打开http://IP:9000即可访问Portainer。

9. 参考资料

[1] 50个最常用的Unix/Linux命令 from gywbd

[2] Linux 下十大命令行下载工具 from Linux中国

[3] linux查看历史命令history from CSDN

[4] Shell Script 流程控制 from 简书

[5] 一些简单的shell脚本实例 from CSDN

[6] Debian安装Docker_from 简书

[7] 从0搭建ShadowsocksR与BBR加速 from bbaaz

[8] Trojan-Go一键安装脚本(Debian/Ubuntu)from ssr中文网

[9] 直接安装和docker安装的区别 from php中文网

[10] Docker下安装MySQL from CSDN

[11] 使用docker安装nginx from 掘金

[12] Linux查看并对外开放端口 from 简书

[13] Debian/Ubuntu/Centos 防火墙放行指定端口 from SunPma’Blog

[14] Docker–删除容器实例和镜像 from 极客分享

[15] Java 服务部署后浏览器无法访问,通过 curl 确可以访问 from V2EX

[16] docker与docker-compose介绍,对比与使用 from 简书

[17] 如何在Debian 9上安装Docker Compose from 腾讯云

[18] mysql 远程访问设置 from 华为云

[19] 使用acme.sh开源项目申请 let‘s encrypt 的免费SSL证书 from Github

[20] 如何使用DNS API from Github

[21] namesilo域名通过acme.sh申请Let’s Encrypt通配符HTTPS证书 from gmloc

[22] let’s encrypt证书,Namesilo用acme申请免费永久,为网站添加ssl加密HTTPS from Bilibili

[23] 宝塔Linux面板安装教程 from 宝塔官方

[24] 搬瓦工VPS查看、修改、新增SWAP分区的大小 from 搬瓦工VPS

[25] Cloudflare 入门教程:使用 Cloudflare 免费 CDN 加速 & 保护自己的网站 from 知乎

[26] Namesilo 域名购买及使用教程 from 知乎

[27] 官方文档:宝塔一键迁移测试版 from 宝塔官方

[28] 使用宝塔一键迁移网站数据 from 主机笔记

[29] Debian/Ubuntu Linux搭建SVN服务器,并设置开机默认启动 from ourjs

[30] SVN运维 from Github

[31] Debian 10 创建开机自启动脚本 from 心底的河流

[32] 解决insserv: warning: script ‘服务名’ missing LSB tags and overrides的问题 from Tan9le

[33] Linux系统如何设置开机自动运行脚本 from 良许Linux

[34] Hexo搭建个人博客并使用Git部署到VPS from 简书

[35] VPS搭建Git服务器 from ocdman

[36] 通过 DockerFile 打包镜像 from cnblog

[37] 如何构建 Docker 镜像 from tkestack

[38] 一文带你彻底学会 Git Hooks 配置 from segmentfault

[39] Hexo搭建个人博客并使用Git部署到VPS from 简书

[40] nginx反向代理多个系统 from CSDN

[41] mysql 数据库 定时自动备份 from 简书

[42] MySQL定时备份数据库 from 知乎

[43] 如何在生产环境下实现每天自动备份mysql数据库 from 51CTO

[44] docker 中 MySQL 备份及恢复 from learnku

[45] Linux修改系统时区 from 简书

[46] Linux升级python至3.x from CSDN

[47] 如何在Debian 10上安装pip from myfreax

[48] Linux下使用docker部署Redis from CSDN

[49] OCI runtime exec failed: exec failed:解决方法 from CSDN

[50] IntelliJ IDEA热部署插件JRebel免费激活图文教程 from 积微成著

[51] 在CenOS/Debian上搭建ReverseProxy反向代理服务 from Github

[52] Python爬虫代理IP池(proxy pool) from Github

[53] redis.exceptions.ResponseError: invalid DB index怎么解决 from Github issue

[54] Python 抓取可用代理IP from CSDN

[55] python 自定义异常和主动抛出异常(raise)的操作 from 华为云

[56] 如何在 Debian 10 上安装和卸载 OpenJDK11/OpenJDK8 from linux265

[57] Linux下部署jar包 from CSDN

[58] Linux Docker springboot jar 日志时间不正确 from CSDN

[59] nohup执行的jar 怎么kill_Linux下java nohup 后台运行关闭后进程停止的原因,不挂断后台运行命令 from CSDN

[60] linux shell脚本 自动重启挂掉的jar包 from CSDN

[61] 使用curl获取URL的重定向目标 from QAStack

[62] docker安装oracle11g(linux环境) from CSDN

[63] Docker 快速安装&搭建 Elasticsearch 环境 from 异常教程

[64] EMQX docker安装及运行 from CSDN

[65] docker安装部署neo4j from 打瞌睡的布偶猫

[66] docker搭建elasticsearch6.8.7并开启x-pack认证 from 程序员宅基地

[67] 如何在Debian 10 Linux上安装Node.js和npm from myfreax

[68] Ubuntu下crontab的安装和使用 from CSDN

[69] Cannot stop or restart a docker container from stackoverflow

[70] Docker启动提示 response from daemon: OCI runtime create failed: container with id exists:XXX:unknown from CSDN

[71] 如何在ubuntu 中彻底删除docker from 腾讯云

[72] docker可视化工具Portainer部署与汉化 from WebEnh

[73] 关于docker容器内部的文件上传和下载 from 代码先锋网

[74] Linux统计文件夹下的文件数目 from SnailTyan

[75] 如何在两个服务器之间传输文件或者文件夹? from CSDN

[76] docker容器打包成镜像和压缩以及解压和载入镜像 from 程序员宝宝

[77] Linux 服务器日常巡检脚本分享 from 知乎

[78] 如何快速删除指定的扩展名文件 from 腾讯云

[79] 手把手教你Debian10安装配置Golang环境,并编译hello world程序 from 老牛博客

[80] 2021 win10下beego的正确安装方法 from ICode9

[81] 利用Dockerfile部署SpringBoot项目 from 51CTO博客

[82] 在docker下部署Python项目 from Python Free

[83] linux磁盘已满,查看哪个文件占用多 from CSDN

[84] Nvidia-smi简介及常用指令及其参数说明 from CSDN