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 安装conda
      11. 2.2.11 安装jdk及Maven
      12. 2.2.12 jar包部署
      13. 2.2.13 kill指定端口号的进程
      14. 2.2.14 监控进程状态
      15. 2.2.15 安装Node.js和npm
      16. 2.2.16 统计文件及文件夹个数
      17. 2.2.17 拷贝同步大量文件
      18. 2.2.18 查看系统发行版
      19. 2.2.19 递归删除某目录下指定扩展名的文件
      20. 2.2.20 安装go及bee工具
      21. 2.2.21 磁盘空间占用分析
      22. 2.2.22 查看GPU基础信息及驱动版本
      23. 2.2.23 查找文件及目录
      24. 2.2.24 查看指定行的nohup.out日志
      25. 2.2.25 进程被kill的问题排查
      26. 2.2.26 ufw防火墙常用命令
      27. 2.2.27 远程文件拷贝命令
      28. 2.2.28 查看目录结构
      29. 2.2.29 安装ffmpeg
      30. 2.2.30 解决IP无法ping通的问题
      31. 2.2.31 查询CPU详细参数
    3. 2.3 vim常用操作
      1. 2.3.1 vim工作模式
      2. 2.3.2 vim常用命令
    4. 2.4 Linux运维脚本
      1. 2.4.1 自动重启挂掉的jar包
      2. 2.4.2 jar包运维脚本
    5. 2.5 使用curl发送接口请求
  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的GPU环境配置
      4. 5.2.4 Docker更换镜像源地址
      5. 5.2.5 Docker常用命令
      6. 5.2.6 清理Docker占用的存储空间
    3. 5.3 Docker Compose环境搭建
    4. 5.4 通过Dockerfile自动构建镜像
      1. 5.4.1 使用Docker部署Springboot项目
      2. 5.4.2 使用Docker部署Flask项目
      3. 5.4.3 使用Docker部署前端项目
    5. 5.5 正式环境的前后端分离项目部署
    6. 5.6 将已有容器部署到其他服务器
  6. 6. 项目运行环境搭建
    1. 6.1 Docker-MySQL环境搭建
      1. 6.1.1 搜索MySQL镜像
      2. 6.1.2 拉取镜像创建实例容器并运行
      3. 6.1.3 创建数据库及用户
      4. 6.1.4 数据库的备份与恢复
      5. 6.1.5 数据库的定时备份
    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 安装ik分词器插件
      4. 6.5.4 安装kibana可视化插件
      5. 6.5.5 ES的导入与导出
      6. 6.5.6 ES的定期自动备份
      7. 6.5.7 使用Logstash将MySQL数据同步到ES
      8. 6.5.8 使用curl命令操作ES
    6. 6.6 Docker-Neo4j环境搭建
      1. 6.6.1 拉取镜像并运行容器
      2. 6.6.2 neo4j的可视化查看
    7. 6.7 Docker-Minio环境搭建
      1. 6.7.1 拉取镜像并运行容器
      2. 6.7.2 minio的管理面板
      3. 6.7.3 使用rclone同步minio数据
    8. 6.8 Docker-MongoDB环境搭建
      1. 6.8.1 拉取镜像并运行容器
      2. 6.8.2 Mongodb创建用户并可视化查看
  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缓存问题
      4. 7.2.4 关闭IPv6支持
    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 搭建LibreTranslate机器翻译API
      1. 8.4.1 LibreTranslate简介
      2. 8.4.2 LibreTranslate部署
    5. 8.5 Docker可视化工具Portainer的部署
      1. 8.5.1 Portainer简介
      2. 8.5.2 Portainer部署
    6. 8.6 使用 verdaccio 搭建私有npm仓库
      1. 8.6.1 verdaccio简介
      2. 8.6.2 verdaccio部署
    7. 8.7 搭建项目管理工具禅道
      1. 8.7.1 禅道简介
      2. 8.7.2 禅道部署
    8. 8.8 搭建 Nginx Proxy Manager 管理面板
      1. 8.8.1 Nginx Proxy Manager 简介
      2. 8.8.2 Nginx Proxy Manager 部署
  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命令:显示当前目录的绝对路径 $(pwd)代表当前目录,常用于shell脚本编写
tree命令:以树状图列出目录的内容
-a 显示所有文件和目录
-C 在文件和目录清单加上色彩,便于区分各种类型
-p 列出权限标示
find命令:从指定的目录开始向下查找满足条件的文件,对找到的文件执行指定操作
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

注:使用tar解压文件到指定目录时出现Not found in archive问题,在 filename.tar.gz 后面加个 -C参数即可。

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
9
$ 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 update && apt-get install vim -y # 安装vim

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

2.2.2 使用Shell脚本

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

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

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

附:Shell脚本接受命令数组传参的示例(./test.sh 1 2 3)

1
2
3
4
5
#!/bin/bash 
for i in [email protected]
do
echo $i
done

另附:Shell脚本遍历数组

1
2
3
4
5
6
#!/bin/bash 
array=("1" "2")
for i in ${array[@]}
do
echo $i
done

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 文件)

另注CentOS的crontab安装及管理命令:

1
2
3
4
5
$ yum install crontabs      // 安装
$ systemctl enable crond // 设为开机启动
$ systemctl start crond // 启动crond服务
$ systemctl status crond // 查看状态
$ vim /etc/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 安装conda

Conda 是一个开源的软件包管理系统和环境管理系统,用于安装多个版本的软件包及其依赖关系,并在它们之间轻松切换。 Conda 是为 Python 程序创建的,适用于 Linux,OS X 和Windows,也可以打包和分发其他软件。

1
2
3
4
5
6
7
$ curl -O https://repo.anaconda.com/archive/Anaconda3-2019.03-Linux-x86_64.sh   // 从官网下载安装脚本
$ bash Anaconda3-2019.03-Linux-x86_64.sh // 阅读协议确认安装,安装完成后再输入yes以便不需要手动将Anaconda添加到PATH
$ conda create -n conda_env python=3.8 // 安装虚拟环境,conda_env是给虚拟环境起的别名(任意即可)
$ conda activate conda_env // 激活虚拟环境
$ conda deactivate // 关闭虚拟环境
$ conda config --set auto_activate_base false // 取消每次启动自动激活conda的基础环境(base)
$ conda info --envs // 查询所有虚拟环境

2.2.11 安装jdk及Maven

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

注:jdk8的安装路径为/usr/lib/jvm/adoptopenjdk-8-hotspot-amd64

另附:CentOS7系统安装jdk8

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ yum search java | grep jdk                               // 查看java版本库
$ yum install java-1.8.0-openjdk java-1.8.0-openjdk-devel // 安装java8
$ ll /usr/lib/jvm // 查看安装位置
$ vi /etc/profile // 设置环境变量(在末尾加上如下内容,JAVA_HOME换成自己的)

#set java environment
JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.322.b06-1.el7_9.x86_64
JRE_HOME=$JAVA_HOME/jre
CLASS_PATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JRE_HOME/lib
PATH=$PATH:$JAVA_HOME/bin:$JRE_HOME/bin
export JAVA_HOME JRE_HOME CLASS_PATH PATH

$ source /etc/profile // 刷新配置,使其生效
$ java -version
$ javac -version

Maven(3.8.4):

Step1:下载Maven

1
2
3
4
$ cd /opt
$ wget https://dlcdn.apache.org/maven/maven-3/3.8.4/binaries/apache-maven-3.8.4-bin.tar.gz
$ tar -zxvf apache-maven-3.8.4-bin.tar.gz
$ rm -f apache-maven-3.8.4-bin.tar.gz

附:可以去 https://maven.apache.org/download.cgi 找所需要的版本。

Step2:配置环境变量

1
$ vi /etc/profile.d/maven.sh

配置信息如下:

1
2
3
export JAVA_HOME=/usr/lib/jvm/adoptopenjdk-8-hotspot-amd64
export M2_HOME=/opt/apache-maven-3.8.4
export PATH=${M2_HOME}/bin:${PATH}

使用source命令重新加载环境变量

1
$ source /etc/profile.d/maven.sh

检查maven的版本:

1
$ mvn --version

Step3:配置maven的settings文件

1
2
$ mkdir /opt/apache-maven-3.8.4/repository
$ vi /opt/apache-maven-3.8.4/conf/settings.xml

配置好localRepository的路径

1
<localRepository>/opt/apache-maven-3.8.4/repository</localRepository>

配置好镜像源地址

1
2
3
4
5
6
<mirror>
<id>alimaven</id>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<mirrorOf>central</mirrorOf>
</mirror>

2.2.12 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.13 kill指定端口号的进程

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

2.2.14 监控进程状态

1
ps -aux | grep 进程号

2.2.15 安装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.16 统计文件及文件夹个数

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

2.2.17 拷贝同步大量文件

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

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

2.2.18 查看系统发行版

1
2
$ cat /etc/issue             // 适用于ubuntu、debian等系统
$ cat /etc/redhat-release // 适用于redhat、centos等系统

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

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

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.20 安装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.21 磁盘空间占用分析

1
2
3
4
5
6
7
$ du -s /* | sort -nr         // 查看哪个目录占用空间大
$ du -h --max-depth=1 // 查看当前目录下文件夹大小情况
$ du -h // 输出各个子目录及文件的大小
$ du -sh // 只输出一个总和大小
$ find / -size +100M // 列出所有大于100M的文件
$ rm -rf /var/log/* // 删除所有log文件
$ cat /dev/null > file.log // 清空指定日志文件

2.2.22 查看GPU基础信息及驱动版本

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

1
$ nvidia-smi -q              // 查询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上每个进程所使用的显存情况。

查看CUDA驱动版本(安装PyTorch之类的深度学习库需要与CUDA驱动版本对应):

1
$ nvcc --version

2.2.23 查找文件及目录

1
2
$ find . -type d -name "tra*"  // 根据名称查找目录
$ find /shell -type f -name '*.sh'|xargs grep 'ufw' // 根据字符串的信息查找文件

2.2.24 查看指定行的nohup.out日志

1
$ tail -fn 100 nohup.out

2.2.25 进程被kill的问题排查

OOM killer:Linux内核Out-Of-Memory killer机制是一种防止内存耗尽影响系统运行而采用的一种自我保护机制。根据内核源码oom_kill.c中的定义,系统会依据“进程占用的内存”,“进程运行的时间”,“进程的优先级”,“是否为 root 用户进程“,”子进程个数和占用内存“,”用户控制参数oom_adj ”等计算一个oom_score值,分数越高就越会被内核优先杀掉。

查看kill日志

1
$ egrep -i 'killed process' /var/log/syslog

含义说明:

  • total-vm:进程总共使用的虚拟内存;
  • anon-rss:虚拟内存实际占用的物理内存;
  • file-rss:虚拟内存实际占用的磁盘空间;

其他的一些分析命令:

1
2
3
4
5
$ dmesg | grep -i -B100 'killed process'  // 查看被kill的所有进程
$ free -h // 查看内存占用情况
$ ps aux|head -1;ps aux|grep -v PID|sort -rn -k +3|head // 查看占用cpu最高的前10个进程
$ ps aux|head -1;ps aux|grep -v PID|sort -rn -k +4|head // 查看占用内存最高的前10个进程
$ sudo ls -l /proc/PID/cwd // 查看进程的调用位置

2.2.26 ufw防火墙常用命令

1
2
3
4
5
$ sudo ufw enable      // 启动ufw防火墙
$ sudo ufw disable // 关闭ufw防火墙
$ sudo ufw status // 查看ufw防火墙状态
$ sudo ufw allow 443 // 允许外部访问443端口
$ sudo ufw deny 443 // 禁止外部访问443端口

2.2.27 远程文件拷贝命令

1
2
$ scp -P port /root/file.txt [email protected]:/root/file.txt   // 远程拷贝文件
$ scp -r -P port /root/dir [email protected]:/root/ // 远程拷贝目录

注:port是目标服务器的端口号(如果两台服务器的端口号相同,可省略该参数),[email protected]是目标服务器的用户和ip。以上命令在发送方输入,之后会提示输入接收方的服务器连接密码。

2.2.28 查看目录结构

1
2
3
$ apt-get install tree  // 安装tree命令(Debian、Ubuntu系统)
$ yum -y install tree // 安装tree命令(CentOS系统)
$ tree -L 2 // 显示当前目录的目录结构,限制目录层级为2

2.2.29 安装ffmpeg

1
2
3
4
5
6
$ vi /etc/apt/sources.list   // 编辑文件,添加如下配置
deb http://www.deb-multimedia.org jessie main

$ sudo apt-get update
$ sudo apt-get install deb-multimedia-keyring
$ sudo apt-get install ffmpeg

2.2.30 解决IP无法ping通的问题

检查内核参数 icmp_echo_ignore_all

1
$ cat /proc/sys/net/ipv4/icmp_echo_ignore_all

若返回结果为0,表示系统允许所有的 ICMP Echo 请求,请检查防火墙设置。

若返回结果为1,表示系统禁止所有的 ICMP Echo 请求,执行如下命令即可解决:

1
$ echo "0" >/proc/sys/net/ipv4/icmp_echo_ignore_all

2.2.31 查询CPU详细参数

总核数 = 物理CPU个数 X 每颗物理CPU的核数

总逻辑CPU数 = 物理CPU个数 X 每颗物理CPU的核数 X 超线程数

1
2
3
4
5
6
$ cat /proc/cpuinfo                                            // 查询CPU型号(完整)
$ cat /proc/cpuinfo | grep name | cut -f2 -d: | uniq -c // 查看CPU型号(简略)
$ cat /proc/cpuinfo| grep "physical id"| sort| uniq| wc -l // 查看物理CPU个数
$ cat /proc/cpuinfo| grep "cpu cores"| uniq // 查看每个物理CPU中core的个数(即核数)
$ cat /proc/cpuinfo| grep "processor"| wc -l // 查看逻辑CPU的个数
$ cat /proc/cpuinfo | grep -e "cpu cores" -e "siblings" | sort | uniq //超线程,分别输出cpu cores和siblings数量,使用超线程则后者翻倍

2.3 vim常用操作

2.3.1 vim工作模式

vim主要包含普通模式、插入模式、末行模式等三种工作模式。

  • 普通模式:启动vim编辑器后默认进入普通模式,该模式中主要完成如光标移动、字符串查找,以及删除、复制、粘贴文件内容等相关操作。
  • 插入模式:该模式中主要的操作就是录入文件内容,可以对文本文件正文进行修改、或者添加新的内容。处于输入模式时,vim编辑器的最后一行会出现“– INSERT –”的状态提示信息。按i可进入插入模式。
  • 末行模式:该模式中可以设置vim编辑环境、保存文件、退出编辑器,以及对文件内容进行查找、替换等操作。处于末行模式时,vim编辑器的最后一行会出现冒号“:”提示符。按ESC可进入末行模式。

2.3.2 vim常用命令

[1] 移动光标操作

1
2
3
4
5
6
7
8
9
10
11
j:向下
20j:向下移动 20 行
k:向上
h:向左
l:向右
0:到行首
^:到行首第一个字符,如果前面有空格的话
$:到行尾
gg:快速到文件头
G:快速到文件尾
50G:跳转到第 50 行

[2] 复制操作

1
2
3
4
5
6
yy:复制一行
8yy:向下复制8行
yw:复制光标开始的一个单词
y$:复制光标到行尾
yfA:复制光标到第一个大写A中间的内容
y2fA:复制光标到第二个大写A中间的内容

[3] 剪切操作

1
2
3
x:向后剪切一个一个字符,如果是在行尾,则为向前剪切
4x:剪切4个
xp:非行尾交换两个字符,如从bs变成sb

[4] 删除操作

删除的内容会放到剪贴板,按p即可粘贴到其他地方。

1
2
3
4
5
dd:删除一行
10dd:删除10行
dw:删除一个单词
df":删除到出现的第一个双引号
d^:删除至行首

[5] 粘贴操作

1
2
p:粘贴复制或剪切的内容
5p:将复制或剪切的内容粘贴5次

[6] 查找和替换操作

在normal模式下按下 / 即可进入查找模式,输入要查找的字符串并按下回车。 Vim会跳转到第一个匹配。 按下 n 查找下一个,按下 N 查找上一个。

1
2
3
4
r+<待替换字母>:将游标所在字母替换为指定字母
R+<待替换字母*n>:连续替换,直到按下Esc
cc:替换整行,即删除游标所在行,并进入插入模式
cw:替换一个单词,即删除一个单词,并进入插入模式

[7] 全选操作

1
2
3
ggvG:全选(高亮显示)
ggyG:全部复制
ggdG:全部删除

[8] 撤销操作

1
2
u:撤销一次操作
U:撤销当前行的所有修改

[9] 保存操作

1
2
wq:保存当前文件并退出
q!:不保存,强制退出

2.4 Linux运维脚本

2.4.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.4.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

2.5 使用curl发送接口请求

使用curl模拟get/post/put/delete请求

其中curl -h查看请求参数的含义 -v 显示请求的信息 -X 选项指定其它协议

1
2
3
4
5
6
7
8
9
get:
curl -v 127.0.0.1:8080/girls/age/18
post:
curl -v 127.0.0.1:8080/girls -d 'age=14&cupSize=C'
curl -v -X POST 127.0.0.1:8080/girls -d 'age=14&cupSize=C'
put:
curl -v -X PUT -d "age=19&cupSize=C" 127.0.0.1:8080/girls/3
delete:
curl -v -X DELETE 127.0.0.1:8080/girls/3

-H ‘xxx’ 带请求头

1
curl -v -H 'ApiKey:xxx' -H 'Sign:xxx' -H 'RequestTime:xxx' -H 'Content-Type:application/json' -H 'User-Agent:PostmanRuntime/7.26.10' -H 'Accept:*/*' -H 'Accept-Encoding:gzip, deflate, br' -H 'Connection:keep-alive' -X POST 192.xxx.xx.xx:xxxx/test/xxxx -d '{"orgCode":"xxx","districtId":"1"}'

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

Debian11系统:

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

CentOS7系统:

1
2
3
4
5
6
7
8
9
10
$ sudo yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-selinux \
docker-engine-selinux \
docker-engine

5.2.2 安装Docker环境

Debian11系统:

方式一:通过脚本安装(推荐)

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

CentOS7系统:

1
2
3
4
5
$ curl -fsSL get.docker.com -o get-docker.sh
$ sudo sh get-docker.sh --mirror Aliyun
$ sudo systemctl enable docker
$ sudo systemctl start docker
$ docker version

5.2.3 Docker的GPU环境配置

在Docker中使用GPU,必须在创建容器时打开--gpus参数,并保证docker的版本在19.03以上。

关于配置Docker使用GPU,其实只用装官方提供的toolkit即可。未配置的话会有Error response from daemon: could not select device driver ““ with capabilities: [[gpu]]的报错,解决办法如下:

1
2
3
4
$ curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add -
$ curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | sudo tee /etc/apt/sources.list.d/nvidia-docker.list
$ sudo apt-get update && sudo apt-get install -y nvidia-container-toolkit
$ sudo systemctl restart docker

5.2.4 Docker更换镜像源地址

缘由:在Dockerfile创建镜像拉取基础镜像时遇到了Get "https://registry-1.docker.io/v2/": net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)报错,原因是连不上官方的源,可修改配置换源解决。

Docker安装后默认没有daemon.json这个配置文件,需要进行手动创建,配置文件的默认路径:/etc/docker/daemon.json,权限为644,内容如下:

1
2
3
4
5
6
7
8
9
{
"registry-mirrors":["https://almtd3fa.mirror.aliyuncs.com"],
"runtimes": {
"nvidia": {
"path": "/usr/bin/nvidia-container-runtime",
"runtimeArgs": []
}
}
}

修改后需要重新加载配置,然后重启docker服务。

1
2
$ sudo systemctl daemon-reload
$ systemctl restart docker.service

5.2.5 Docker常用命令

[1] 搜索及拉取docker镜像

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

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

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

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

1
2
3
4
5
6
$ docker start [CONTAINER ID/NAMES]   # 开启指定docker容器实例
$ docker stop [CONTAINER ID/NAMES] # 停止指定docker容器实例
$ docker restart [CONTAINER 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 [CONTAINER ID/NAMES]   # 强制删除指定docker容器实例(删除前需先停止实例)
$ docker rmi -f [CONTAINER 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] 让容器使用GPU环境

docker run 的时候加上 –gpus all 即可

1
--gpus all

[9] 在docker容器外执行容器内的命令

有时候我们想执行某个容器的某条命令,但又不想进入容器内,可通过如下命令示例实现:

1
$ docker exec -it [CONTAINER ID/NAMES] /bin/bash -c 'cd /code && python test.py'

注:如果遇到the input device is not a TTY问题,去掉t即可,即:

1
$ docker exec -i [CONTAINER ID/NAMES] /bin/bash -c 'cd /code && python test.py'

[10] docker的跨容器调用

需求情景:爬虫项目和定时任务项目分别在两个容器中部署的,想要在定时任务项目里编写脚本调用爬虫项目中的具体执行文件。

我们可以通过挂载docker.sockdocker命令行客户端实现用docker exec来间接调用。只需要在docker run的时候挂载如下路径即可:

1
-v /var/run/docker.sock:/var/run/docker.sock -v /usr/bin/docker:/usr/bin/docker

[11] 给docker镜像打Tag

1
$ docker tag [IMAGEID] [REPOSITORY]:[TAG]

[12] 给docker容器设置开机自启

1
$ docker update [CONTAINER ID/NAMES] --restart=always

[13] 显示docker容器占用的系统资源

1
2
3
4
$ docker stats               // stats命令默认会每隔1秒钟刷新一次输出的内容直到你按下ctrl + c
$ docker stats --no-stream // 如果不想持续的监控容器使用资源的情况,可以通过 --no-stream 选项输出当前的状态
$ docker stats --no-stream [CONTAINER ID/NAMES] // 只输出指定容器的
$ docker stats --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}" // 格式化输出结果,可以只输出部分指标项

[14] 容器进程查看

1
2
$ ps -ef   // 查看容器内进程(需要先进入容器内部)
$ docker ps -q | xargs docker inspect --format '{{.State.Pid}}, {{.Name}}' | grep "PID" // 根据PID查docker名

另注:在外部查看指定docker容器的进程号

1
$ docker container top [CONTAINER ID/NAMES]

[15] 查看容器内系统版本

1
$ cat /etc/*release     // 查看容器内系统版本(需要先进入容器内部)

[16] 无ENTRYPOINT方式启动

如果是直接执行的代码,写Dockerfile时就不需要加ENTRYPOINT了,然后用以下命令进入容器:

1
$ docker run -it --name [CONTAINER ID/NAMES] [IMAGE ID/NAMES] /bin/bash

如果要覆盖原先Dockerfile里的ENTRYPOINT配置,加个--entrypoint /bin/bash即可。

1
$ docker run -it --entrypoint /bin/bash --name [CONTAINER ID/NAMES] [IMAGE ID/NAMES]

[17] 查看指定容器的元数据

1
2
3
$ docker inspect [CONTAINER ID/NAMES]  // 查看指定容器的元数据
$ docker inspect [CONTAINER ID/NAMES] | grep -i Status -A 10 // 查看容器状态及退出原因
$ docker image inspect [IMAGE NAMES]:latest |grep -i version // 查看指定latest镜像的版本号

5.2.6 清理Docker占用的存储空间

[1] docker空间清理

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

[2] 查看并清空容器日志

在Linux上,Docker容器日志一般存放在/var/lib/docker/containers/container_id/下面, 以json.log结尾。

手动处理容器日志:

1
2
$ docker inspect --format='{{.LogPath}}' [CONTAINER ID/NAMES]       # 查看指定容器的日志
$ echo |sudo tee $(docker inspect --format='{{.LogPath}}' [CONTAINER ID/NAMES]) # 清空指定容器的日志

批量查找容器日志find_docker_log.sh:

1
2
3
4
5
6
7
8
9
10
#!/bin/sh

echo "======== docker containers logs file size ========"

logs=$(find /var/lib/docker/containers/ -name *-json.log)

for log in $logs
do
ls -lh $log
done

批量清空容器日志 clear_docker_log.sh:

1
2
3
4
5
6
7
8
9
10
11
12
13
#!/bin/sh 

echo "======== start clean docker containers logs ========"

logs=$(find /var/lib/docker/containers/ -name *-json.log)

for log in $logs
do
echo "clean logs : $log"
cat /dev/null > $log
done

echo "======== end clean docker containers logs ========"

注:以上清理日志的方法治标不治本,可通过以下方式设置Docker容器日志大小治本。

方案一:设置一个容器服务的日志大小上限

设置一个容器服务的日志大小上限

1
2
3
--log-driver json-file  #日志驱动
--log-opt max-size=[0-9+][k|m|g] #文件的大小
--log-opt max-file=[0-9+] #文件数量

方案二:全局设置

编辑文件/etc/docker/daemon.json, 增加以下日志的配置:

1
2
"log-driver":"json-file",
"log-opts": {"max-size":"500m", "max-file":"3"}

解释说明:

  • max-size=500m,意味着一个容器日志大小上限是500M,
  • max-file=3,意味着一个容器有三个日志,分别是id+.json、id+1.json、id+2.json。

然后重启docker守护进程

1
2
$ systemctl daemon-reload
$ systemctl restart docker

注:设置的日志大小限制,只对新建的容器有效。

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
11
12
# 基于java8镜像创建新镜像
FROM java:8
# 作者
MAINTAINER eula
# 将jar包添加到容器中并更名为app.jar
COPY test-project-0.0.1-SNAPSHOT.jar /app.jar
# 安装vim命令
RUN apt-get update && apt-get install vim -y
# 放行端口
EXPOSE 8888
# 后台运行jar包
ENTRYPOINT ["nohup","java","-jar","/app.jar","&"]

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

1
2
3
4
$ 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 // 通过镜像运行容器
$ docker update test-springboot --restart=always // 设置开机自启

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
15
16
# 基于python3.7镜像创建新镜像
FROM python:3.7
# 创建容器内部目录
RUN mkdir /code
# 将项目复制到内部目录
ADD test-project /code/
# 切换到工作目录
WORKDIR /code
# 安装项目依赖
RUN pip install -r requirements.txt
# 安装vim命令
RUN apt-get update && apt-get install vim -y
# 放行端口
EXPOSE 5000
# 启动项目
ENTRYPOINT ["nohup","python","server.py","&"]

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

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

5.4.3 使用Docker部署前端项目

Step1:将前端项目打包,生成dist文件(或者其他的),编写Dockerfile,示例如下:

1
2
3
4
5
6
7
8
# 设置基础镜像
FROM nginx
# 将dist文件中的内容复制到 /usr/share/nginx/html/这个目录下面
COPY dist/ /usr/share/nginx/html/
# 安装vim命令
RUN apt-get update && apt-get install vim -y
# 放行9500端口
EXPOSE 9500

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

1
2
3
4
$ cd /root/deploy                                                     // 切换到存放项目和Dockerfile的目录
$ docker build -t test-web-image . // 使用Dockerfile构建镜像
$ docker run -d -p 9500:80 --name test-web test-web-image:latest // 通过镜像运行容器
$ docker update test-web --restart=always // 设置开机自启

访问地址:http://ip:9500

注:容器内nginx的默认端口是80,如要使用其他端口,请修改nginx配置。以下是容器内的几个重要目录,如有需要可挂载出来。

1
2
3
/etc/nginx/conf.d                                                     // Nginx配置目录
/usr/share/nginx/html // Nginx存放资源的目录
/var/log/nginx // Nginx日志目录

另注:如果访问页面时出现403问题,进入容器内修改权限即可。

1
2
$ docker exec -it test-web /bin/bash
$ chmod -R 755 /usr/share/nginx/html

5.5 正式环境的前后端分离项目部署

正式环境使用docker network对Docker容器进行统一管理,像数据库这种提供服务的,就不对外提供端口了,各容器之间通过hostname进行内部通信。

下面以一个Springboot + Vue的前后端分离项目(项目依赖于MySQL、Redis、 Elasticsearch、Emqx)为例。

Step1:创建docker network

1
$ docker network create yoyo

注:可使用 docker network ls 查看已创建的网络

Step2:创建项目依赖环境,并添加到网络里去

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$ docker run -itd --name yoyo_mysql -h yoyo_mysql --network yoyo \
-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] \
mysql:5.7 --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
$ docker update yoyo_mysql --restart=always

$ docker run -itd --name yoyo_redis -h yoyo_redis --network yoyo redis:3.2.8 --requirepass "mypassword"
$ docker update yoyo_redis --restart=always

$ docker run -itd --name yoyo_es -h yoyo_es --network yoyo \
-e "discovery.type=single-node" \
-e ES_JAVA_OPTS="-Xms200m -Xmx200m" \
elasticsearch:7.16.2
$ docker update yoyo_es --restart=always

$ docker run -itd --name yoyo_emqx -h yoyo_emqx --network yoyo -p 1883:1883 -p 18083:18083 emqx/emqx
$ docker update yoyo_emqx --restart=always

注:创建容器时要用 -h 指定 hostname,–network 指定网络,除Emqx外不需要 -p 对外映射端口号。

Step3:项目打包并修改配置文件

将Springboot项目打成jar包,Vue项目打成dist包。除此之外,需要修改Springboot项目的配置文件(把项目依赖的MySQL、Redis、 Elasticsearch、Emqx环境地址由原来的ip:port改成 docker 的 hostname),这里采用包外配置。

这部分内容有不熟悉的可以参考我的 Springboot和一些主流框架的整合样例前端开发环境配置及Vue开发样例 两篇博客。

Step4:准备项目部署所需要的文件

项目部署所需要文件的目录结构如下:

1
2
3
4
5
6
7
8
9
├── config
│   ├── application-prod.properties
│   └── application.properties
├── dist.tar.gz
├── Dockerfile
├── jdk-8u202-linux-x64.tar.gz
├── proxy.conf
├── yoyo_web.conf
└── web_manage-0.0.1.jar

[1] 准备 java8 环境(jdk-8u202-linux-x64.tar.gz)

去官网下载一个linux版的jdk,jdk-8u202-linux-x64.tar.gz 的官网下载地址

[2] 准备 nginx 配置文件 (yoyo_web.conf、proxy.conf)

yoyo_web.conf(需要修改后端的接口地址和前端文件的存放路径)

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
upstream dev_yoyo_web {
server 127.0.0.1:8080 weight=1 max_fails=1 fail_timeout=10s;
}
server {
listen 80;
server_name 127.0.0.1;
location / {
gzip on;
gzip_vary on;
gzip_min_length 1k;
gzip_buffers 16 16k;
gzip_http_version 1.1;
gzip_comp_level 9;
gzip_types text/plain application/javascript application/x-javascript text/css text/xml text/javascript application/json;
root /usr/share/nginx/html;
index index.html;
try_files $uri $uri/ /index.html?$query_string;
}

location ~* ^(/login|/logout|/api/|/auth/) {
proxy_pass http://dev_yoyo_web;
client_max_body_size 48m;
include proxy.conf;
}
}

proxy.conf(无需修改)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
proxy_connect_timeout 900s;
proxy_send_timeout 900;
proxy_read_timeout 900;
proxy_buffer_size 32k;
proxy_buffers 4 64k;
proxy_busy_buffers_size 128k;
proxy_redirect off;
proxy_hide_header Vary;
proxy_set_header Accept-Encoding '';
proxy_set_header Referer $http_referer;
proxy_set_header Cookie $http_cookie;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;

[3] 准备Dockerfile

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
# 设置基础镜像
FROM nginx

# 安装java8环境
WORKDIR /usr
RUN mkdir /usr/local/java
ADD jdk-8u202-linux-x64.tar.gz /usr/local/java
RUN ln -s /usr/local/java/jdk1.8.0_202 /usr/local/java/jdk
ENV JAVA_HOME /usr/local/java/jdk
ENV JRE_HOME ${JAVA_HOME}/jre
ENV CLASSPATH .:${JAVA_HOME}/lib:${JRE_HOME}/lib
ENV PATH ${JAVA_HOME}/bin:$PATH

# 放置前端代码及nginx配置
ADD dist.tar.gz /usr/share/nginx/html/dist
COPY yoyo_web.conf /etc/nginx/conf.d/default.conf
COPY proxy.conf /etc/nginx

# 放置后端代码及包外配置
RUN mkdir /storage
COPY web_manage-0.0.1.jar /storage
COPY config /storage

# 安装vim命令
RUN apt-get update && apt-get install vim -y

# 放行访问端口
EXPOSE 9500

注:前端包建议打成tar.gz格式,ADD命令会自动对其进行解压。而zip、rar等格式不会自动解压,还需要进入容器自行解压。

Step5:打包镜像并创建容器启动项目

1
2
3
4
5
$ docker build -t 'yoyo_web' .
$ docker run -itd --name yoyo_web -h yoyo_web --network yoyo -p 9500:80 -p 8080:8080 yoyo_web
$ docker exec -it yoyo_web /bin/bash
$ cd /storage
$ nohup java -jar web_manage-0.0.1.jar

启动成功后,项目就部署好了,Chrome访问 IP:9500地址即可查看。

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

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

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

注意事项:

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

[2] 直接对设置挂载的容器打包,会导致通过挂载加进去的文件并没有加进去(打出来的镜像不包含挂载进去的文件),可以再创建个不挂载的容器,把文件替换进去,再对这个不挂载的容器打包。

6. 项目运行环境搭建

6.1 Docker-MySQL环境搭建

6.1.1 搜索MySQL镜像

1
$ docker search mysql

docker-mysql

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

6.1.2 拉取镜像创建实例容器并运行

1
2
3
4
5
6
7
8
9
$ docker pull mysql:5.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
$ docker update mysql --restart=always

命令解释说明:

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:设置校对集

说明:如果是挂载已有的其他服务器数据,可能会出现用户权限问题,如果网络是通的,建议使用Navicat的数据传输功能(工具——数据传输——配置源与目标链接——选择需要传输的数据表即可),数据传输速度很快。

6.1.3 创建数据库及用户

在本地使用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 '你的用户名'@'%' IDENTIFIED BY '你的密码' WITH GRANT OPTION;

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

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

6.1.4 数据库的备份与恢复

[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.5 数据库的定时备份

实际在生产环境上,我们不会每天都去手动备份。可以写一个脚本出来,完成这项操作,然后用 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.5 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
8
9
$ docker pull elasticsearch:7.16.2
$ docker run -d --name es \
-p 9200:9200 -p 9300:9300 \
-v /mydocker/es/data:/usr/share/elasticsearch/data \
-v /mydocker/es/config:/usr/share/elasticsearch/config \
-v /mydocker/es/plugins:/usr/share/elasticsearch/plugins \
-e "discovery.type=single-node" -e ES_JAVA_OPTS="-Xms1g -Xmx1g" \
elasticsearch:7.16.2
$ docker update es --restart=always

注意事项:

1)Elasticsearch请选择7.16.0之后的版本,之前的所有版本都使用了易受攻击的 Log4j2版本,存在严重安全漏洞。

2)ES_JAVA_OPTS="-Xms1g -Xmx1g"只是一个示例,内存设置的少了会导致数据查询速度变慢,具体设置多少要根据业务需求来定,一般而言公司的实际项目要设置8g内存以上。

数据挂载遇到的问题:

[1] 数据锁定问题

报错信息:java.lang.IllegalStateException: failed to obtain node locks, tried [[/usr/share/elasticsearch/data]] with lock id [0]; maybe these locations are not writable or multiple nodes were started without increasing

产生原因:ES在运行时会在/data/nodes/具体分片目录里生成一个node.lock文件,由于我是在运行期scp过来的挂载数据,这个也被拷贝过来了,导致数据被锁定。

解决办法:删掉/data/nodes/具体分片/node.lock文件即可

[2] data目录权限问题

解决办法:进入容器内部,把data目录的权限设置为777即可

[3] 集群与单节点问题

解决办法:修改config/elasticsearch.yml里的集群配置即可,如果原来是集群,现在要单节点,就把集群配置去掉。

[4] 堆内存配置问题

报错信息:initial heap size [8589934592] not equal to maximum heap size [17179869184]; this can cause resize pauses

解决办法:-Xms 与 -Xmx 设置成相同大小的内存。

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 // 然后设置一大堆账号密码

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

elasticvue

6.5.3 安装ik分词器插件

项目简介:IK 分析插件将 Lucene IK 分析器集成到 elasticsearch 中,支持自定义字典。

项目地址:https://github.com/medcl/elasticsearch-analysis-ik

安装方式:去Releases下载对应ES版本的ik分词器插件,然后上传到Plugins目录将其挂载到容器内。

测试方式:k分词器有2种算法:ik_smart和ik_max_word,下面我们通过postman工具来测试ik分词器的分词算法。

[1] 测试ik_smart分词

请求url:http://ip:9200/_analyze

请求方式:get

请求参数:

1
2
3
4
{
"analyzer":"ik_smart",
"text":"我爱你,特靠谱"
}

[2] 测试ik_max_word分词

请求url:http://ip:9200/_analyze

请求方式:get

请求参数:

1
2
3
4
{
"analyzer":"ik_max_word",
"text":"我爱你,特靠谱"
}

上面测试例子可以看到,不管是ik_smart还是ik_max_word算法,都不认为”特靠谱”是一个关键词(ik分词器的自带词库中没有有”特靠谱”这个词),所以将这个词拆成了三个词:特、靠、谱。

自定义词库:ik分词器会把分词库中没有的中文按每个字进行拆分。如果不想被拆分,那么就需要维护一套自己的分词库。

Step1:进入ik分词器路径/config目录,新建一个my.dic文件,添加一些关键词,如”特靠谱”、”靠谱”等,每一行就是一个关键词。

Step2:修改配置文件IKAnalyzer.cfg.xml,配置<entry key="ext_dict"></entry>

1
2
3
4
5
6
7
8
9
10
11
12
13
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<comment>IK Analyzer 扩展配置</comment>
<!--用户可以在这里配置自己的扩展字典 -->
<entry key="ext_dict">my.dic</entry>
<!--用户可以在这里配置自己的扩展停止词字典-->
<entry key="ext_stopwords"></entry>
<!--用户可以在这里配置远程扩展字典 -->
<!-- <entry key="remote_ext_dict">words_location</entry> -->
<!--用户可以在这里配置远程扩展停止词字典-->
<!-- <entry key="remote_ext_stopwords">words_location</entry> -->
</properties>

Step3:重启ES,并再次使用Postman测试上述请求,发现”特靠谱”、”靠谱”等将其视为一个词了。

6.5.4 安装kibana可视化插件

下载与ES版本相同的Kibana

1
2
3
4
5
6
$ mkdir -p /root/kibana
$ cd /root/kibana
$ wget https://artifacts.elastic.co/downloads/kibana/kibana-7.16.2-linux-x86_64.tar.gz
$ tar -zxvf kibana-7.16.2-linux-x86_64.tar.gz
$ cd /root/kibana/kibana-7.16.2-linux-x86_64
$ vi /config/kibana.yml

修改配置文件内容如下(用不到的我这里给删掉了,原配置文件有着很详尽的英文说明):

1
2
3
4
5
6
server.port: 5601
server.host: "ip"
elasticsearch.hosts: ["http://ip:9200"]
elasticsearch.username: "username"
elasticsearch.password: "password"
i18n.locale: "zh-CN"

启动kibana:

1
2
$ cd /root/kibana/kibana-7.16.2-linux-x86_64/bin # 进入可执行目录
$ nohup /root/kibana/kibana-7.16.2-linux-x86_64/bin/kibana & # 启动kibana

说明:如果是root用户,会报Kibana should not be run as root. Use --allow-root to continue.的错误,建议切换别的用户去执行,如果就是想用root用户启动,则使用nohup /mydocker/kibana/kibana-7.16.2-linux-x86_64/bin/kibana --allow-root &

启动成功后,浏览器打开http://ip:5601/地址,用es的用户名和密码进行登录,就可以使用了。

Kibana管理面板

关闭kibana:

1
2
$ ps -ef | grep kibana
$ kill -9 [PID]

6.5.5 ES的导入与导出

方案一:使用elasticdump插件进行导入导出

elasticdump:Elasticsearch的导入导出工具

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的内容即可。

方案二:使用esm工具进行导入导出

esm:一个 Elasticsearch 迁移工具

1
2
3
4
5
$ mkdir -p /root/esm
$ cd /root/esm
$ wget https://github.com/medcl/esm/releases/download/v0.6.1/migrator-linux-amd64
$ chmod u+x migrator-linux-amd64
$ ./migrator-linux-amd64 -s http://source_ip:9200 -m source_username:source_password -x "source_index" -d http://target_ip:9200 -n target_username:target_password -y "target_index"

注:可使用./migrator-linux-amd64 --help查看使用帮助

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
-s, --source=源elasticsearch实例,即:http://localhost:9200
-q, --query= 查询源elasticsearch实例,迁移前过滤数据,即:name:medcl
-d, --dest= 目标elasticsearch实例,即:http://localhost:9201
-m, --source_auth= 源elasticsearch实例的基本认证,即:user:pass
-n, --dest_auth=目标elasticsearch实例的基本认证,即:user:pass
-c, --count= 一次文档数:即滚动请求中的“大小”(默认值:5000)
--buffer_count= 内存中缓冲文档的数量(默认值:10000)
-w, --workers= 批量工作线程的并发数(默认值:1)
-b, --bulk_size= 以 MB 为单位的批量大小(默认值:5)
-t, --time= 滚动时间(默认:10m)
--sliced_scroll_size= 切片滚动的大小,要使其正常工作,大小应> 1(默认值:1)
-f, --force 在复制前删除目标索引
-a, --all 复制以 . 开头的索引。和 _
--copy_settings 从源复制索引设置
--copy_mappings 从源复制索引映射
--shards= 在新创建的索引上设置多个分片
-x, --src_indexes= 要复制的索引名称,支持正则表达式和逗号分隔列表(默认值:_all)
-y, --dest_index= 要保存的索引名,只允许一个索引名,如果不指定将使用原始索引名
-u, --type_override=覆盖类型名称
--green 在转储前等待两台主机集群状态变为绿色。否则黄色是可以的
-v, --log= 设置日志级别,选项:trace,debug,info,warn,error (默认: INFO)
-o, --output_file= 将源索引的文件输出到本地文件中
-i, --input_file= 从本地转储文件索引
--input_file_type= 输入文件的数据类型,选项:dump、json_line、json_array、log_line(默认:dump)
--source_proxy= 设置代理为源http连接,即:http://127.0.0.1:8080
--dest_proxy= 设置代理为目标http连接,即:http://127.0.0.1:8080
--refresh 迁移完成后刷新
--fields= 过滤源字段,逗号分隔,即:col1,col2,col3,...
--rename= 重命名源字段,逗号分隔,即:_type:type, name:myname
-l, --logstash_endpoint=目标logstash tcp端点,即:127.0.0.1:5055
--secured_logstash_endpoint 目标 logstash tcp 端点由 TLS 保护
--repeat_times= 将数据从源重复N次到目标输出,使用对齐参数regenerate_id来放大数据大小
-r, --regenerate_id 为文档重新生成 id,这将覆盖数据源中存在的文档 id
--compress 使用gzip压缩流量
-p, --sleep= 在每个批量请求后睡眠 N 秒(默认值:-1)

方案三:使用python脚本进行导入导出

代码已在Github上开源,项目地址为:https://github.com/Logistic98/es-data-transfer

详见我的另一篇博客:使用Flask封装集成深度学习算法

6.5.6 ES的定期自动备份

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

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

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.5 Crontab定时任务”.

6.5.7 使用Logstash将MySQL数据同步到ES

[1] 安装Logstash

项目地址:https://github.com/elastic/logstash

下载地址:https://www.elastic.co/guide/en/logstash/7.14/installing-logstash.html#_apt

处理流程:

logstash处理流程

注意要有 java8 的环境(没有的话先参照 2.2.11 安装 jdk8),然后要安装跟ES一样的版本,以下是 Logstash 的安装命令:

1
2
3
$ mkdir -p /root/mysql_sync_es && cd /root/mysql_sync_es
$ wget https://artifacts.elastic.co/downloads/logstash/logstash-7.16.2-linux-x86_64.tar.gz
$ tar -zxvf logstash-7.16.2-linux-x86_64.tar.gz

[2] 配置Logstash

Step1: 下载一个 mysql-connector-java-5.1.34.jar

1
$ wget https://repo1.maven.org/maven2/mysql/mysql-connector-java/5.1.34/mysql-connector-java-5.1.34.jar

Step2:创建同步配置文件

1
2
$ mkdir -p /root/mysql_sync_es/last_update_data
$ vim db_table_sync.conf

单表同步的配置示例如下:

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
76
77
78
79
80
81
input {
jdbc {
# 类型(建议用表名即可)
type => "db_table"
# 数据库连接地址
jdbc_connection_string => "jdbc:mysql://ip:port/db?useUnicode=true&characterEncoding=utf8&useSSL=false"
# 数据库用户名
jdbc_user => "root"
# 数据库密码
jdbc_password => "password"
# 判断数据库连接是否可用,默认false不开启
jdbc_validate_connection => true
# MySQL依赖包路径
jdbc_driver_library => "/root/mysql_sync_es/mysql-connector-java-5.1.34.jar"
# MySQL驱动
jdbc_driver_class => "com.mysql.jdbc.Driver"
# 开启分页查询(默认false不开启)
jdbc_paging_enabled => true
# 单次分页查询条数(默认100000,若字段较多且更新频率较高,建议调低此值)
jdbc_page_size => "1000"
# 编码转换
codec => plain { charset => "UTF-8"}
# 执行的sql语句
statement => "SELECT id, uid, user_name, description, DATE_FORMAT( create_time, '%Y-%m-%d %H:%i:%S' ) create_time, DATE_FORMAT( insert_time, '%Y-%m-%d %H:%i:%S' ) insert_time, DATE_FORMAT( ifnull( update_time, insert_time ), '%Y-%m-%d %H:%i:%S' ) update_time FROM table WHERE update_time > : sql_last_value"
# 是否记录上次执行结果,true表示会将上次执行结果的tracking_column字段的值保存到last_run_metadata_path指定的文件中;
record_last_run => true
# 需要记录查询结果某字段的值时,此字段为true,否则默认tracking_column为timestamp的值
use_column_value => true
# 需要记录的字段,用于增量同步,需是数据库字段
tracking_column => "update_time"
# 需要记录的字段类型,值可以是:numeric,timestamp,默认值为“numeric”
tracking_column_type => "timestamp"
# record_last_run上次数据存放位置
last_run_metadata_path => "/root/mysql_sync_es/last_update_data/db_table_last_update_time"
# 是否将字段名转换为小写,默认true(如果有数据序列化、反序列化需求,建议改为false)
lowercase_column_names => false
# 是否清除last_run_metadata_path的记录,需要增量同步时此字段必须为false;
clean_run => false
# crontab定时任务,目前设置的是每小时同步一次,默认设置为每分钟同步一次
schedule => "* */1 * * *"
}
}

filter {
if [type] == "db_table" {
mutate {
# 重命名字段
rename => {
"user_name" => "userName"
"create_time" => "createTime"
"insert_time" => "insertTime"
"update_time" => "updateTime"
}
# 添加额外字段
add_field => {
"field" => "Field"
}
}
}
}

output {
if [type] == "db_table" {
stdout {
# JSON格式输出
codec => json_lines
}
elasticsearch {
# ES索引名
index => "db_table"
# ES连接地址
hosts => "ip:port"
# 文档id
document_id => "%{id}"
# ES用户名
user => elastic
# ES密码
password => password
}
}
}

注:多表配置和单表配置的区别在于input模块的jdbc模块有几个type,output模块就需对应有几个type。document_id => "%{id}"是根据id去更新(如果不会更新旧数据,这个去掉即可),如果有重命名,%{}里应该是重命名之后的。

[3] 启动Logstash开始数据同步

1
2
3
4
5
方式一:指定具体的配置文件
$ nohup /root/mysql_sync_es/logstash-7.16.2/bin/logstash -f /root/mysql_sync_es/db_table_sync.conf --path.data=/root/mysql_sync_es/data/db_table_sync_data &

方式二:指定配置文件目录(目录里所有的配置文件都会执行)
$ nohup /root/mysql_sync_es/logstash-7.16.2/bin/logstash -f /root/mysql_sync_es --path.data=/root/mysql_sync_es/data &

注意事项:

1)需要指定 path.data,否则会报如下错误

1
Logstash could not be started because there is already another instance using the configured data directory.  If you wish to run multiple instances, you must change the "path.data" setting

2)可以提前写好用于启动的 shell 脚本,这样就更方便启动了。

3)关闭 Logstash 可通过 kill 进程来实现

1
2
$ ps -ef | grep logstash
$ kill -9 [PID]

6.5.8 使用curl命令操作ES

1
2
3
4
5
6
7
8
// 查询所有索引
$ curl -u 用户名:密码 http://ip:port/_cat/indices

// 删除索引(包含结构)
$ curl -u 用户名:密码 -XDELETE http://ip:port/索引名

// 清空索引(不包含结构)
$ curl -u 用户名:密码 -XPOST 'http://ip:port/索引名/_delete_by_query?refresh&slices=5&pretty' -H 'Content-Type: application/json' -d'{"query": {"match_all": {}}}'

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/ 查看即可。

6.7 Docker-Minio环境搭建

6.7.1 拉取镜像并运行容器

1
2
3
4
5
6
7
8
9
10
$ docker pull minio/minio
$ mkdir -p /home/data/minio/data
$ mkdir -p /home/data/minio/config
$ docker run -d --restart always \
-p 9000:9000 -p 9001:9001 --name minio \
-e "MINIO_ACCESS_KEY=admin" \
-e "MINIO_SECRET_KEY=password" \
-v /home/data/minio/data:/data \
-v /home/data/minio/config:/root/.minio \
minio/minio server --console-address ":9001" /data

注:密码不可以设置的太简单了(会导致创建失败),出现此问题请查看容器日志。

6.7.2 minio的管理面板

浏览器打开:http://IP:9001 查看即可。MINIO_ACCESS_KEY为账号,MINIO_SECRET_KEY为密码。进去之后创建存储桶,即可进行使用。

minio console

6.7.3 使用rclone同步minio数据

Rclone 是一个开源的命令行程序,用来同步文件和目录进或者出云存储系统,它旨在成为”云存储的rsync”。除了minio之外,也支持其他云存储的同步。

项目地址:https://github.com/rclone/rclone 官方文档:http://docs.minio.org.cn/docs/master/rclone-with-minio-server

Step1:安装rclone

1
$ curl https://rclone.org/install.sh | sudo bash

Step2:新建配置文件

/root/.config/rclone/rclone.conf 路径新建配置文件,内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
[oldminio]
type = s3
provider = Minio
env_auth = false
access_key_id = user1
secret_access_key = password1
region = cn-east-1
endpoint = http://ip1:9000
location_constraint =
server_side_encryption =

[newminio]
type = s3
provider = Minio
env_auth = false
access_key_id = user1
secret_access_key = password1
region = cn-east-1
endpoint = http://ip2:9000
location_constraint =
server_side_encryption =

注:只需修改 access_key_id、secret_access_key、endpoint的值即可,可添加多个数据源。

Step3:进行数据同步

1
$ rclone sync -P oldminio:mybucket newminio:mybucket

解释说明:

  • 使用 sync 参数,同步有差异的数据
  • -P 显示详细过程
  • mybucket 桶名称,新minio没有则自动创建

注意事项:

  • 注意存储桶的访问策略,如果为Public可以直接访问,如果为Private不可访问,如果为Custom请在有权限访问的服务器上进行操作。
  • rclone是一个数据同步工具,支持增量更新,可用于minio数据的跨网传输。

6.8 Docker-MongoDB环境搭建

6.8.1 拉取镜像并运行容器

1
2
3
$ docker pull mongo:latest
$ mkdir -p /mydocker/mongodb/data
$ docker run -itd --name mongodb -v /mydocker/mongodb/data:/data/db -p 27017:27017 mongo --auth

参数说明:–auth:需要密码才能访问容器服务,启动容器后进入容器为用户设置密码

6.8.2 Mongodb创建用户并可视化查看

1
2
3
4
5
6
$ docker exec -it mongodb mongo admin

# 创建一个名为 admin,密码为 123456 的用户。
> db.createUser({ user:'admin',pwd:'123456',roles:[{ role:'userAdminAnyDatabase', db:'admin'},"readWriteAnyDatabase"]});
# 尝试使用上面创建的用户信息进行连接。
> db.auth('admin', '123456')

Mongodb使用Navicat工具连接即可(验证数据库那栏空着就行)

7. 网站环境搭建

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

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

Chrome一直在推动https,所有的http协议网站被标记为不安全,如果再不对网站进行https改造的话,那么可能会对信任度造成一定的影响,所以说对一个面向用户的网站来说,开启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.2.4 关闭IPv6支持

进入 CloudFlare 后台,在网站配置的“Network”下面,可以看到“IPv6 兼容性”的选项,但是比较坑的一点就是图形界面不让你操作,只能使用API去操作。

IPv6 兼容性

我们可以借助 CloudFlare 的 API 来实现关闭 IPv6,首先打开我们的 账户 获取 API Key。

API密钥

点击Global API Key后面的查看即可。

接下来使用curl命令发送请求即可,我们只需要修改邮箱和密钥处即可。

1
$ curl -X PATCH "https://api.cloudflare.com/client/v4/zones/023e105f4ecef8ad9ca31a8372d0c353/settings/ipv6" -H "X-Auth-Email: 邮箱" -H "X-Auth-Key: 密钥" -H "Content-Type: application/json" --data '{"value":"off"}'

请求成功后,再回到IPv6的界面,发现它已经被成功关闭啦。

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 搭建LibreTranslate机器翻译API

8.4.1 LibreTranslate简介

一个开源的、可以自行搭建的翻译服务,支持多种语言的互相翻译,包括中文。翻译的准确度不如商业API,但它是永久免费的。服务器上部署LibreTranslate共计需要大约13GB的存储空间。

8.4.2 LibreTranslate部署

1
2
$ docker run -itd -p 5000:5000 --name libretranslate libretranslate/libretranslate
$ docker logs -f libretranslate --tail 100

注:创建容器后会自动下载语言包,这个过程会比较慢,等待它安装完毕后,浏览器访问http://ip:5000即可查看以下Web页面。

LibreTranslate

8.5 Docker可视化工具Portainer的部署

8.5.1 Portainer简介

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

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

8.5.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。

8.6 使用 verdaccio 搭建私有npm仓库

8.6.1 verdaccio简介

项目简介:verdaccio是一个简单的、零配置要求的本地私有 npm 注册表。无需整个数据库即可开始!Verdaccio 开箱即用, 拥有自己的小型数据库,并且能够代理其他注册表,并在此过程中缓存下载的模块。

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

8.6.2 verdaccio部署

Step1:拉取镜像并创建容器挂载目录

1
2
3
4
5
6
7
8
9
$ docker pull verdaccio/verdaccio
$ docker run -itd --name verdaccio -p 4873:4873 verdaccio/verdaccio
$ mkdir -p /mydocker/verdaccio
$ docker cp verdaccio:/verdaccio/storage /mydocker/verdaccio/storage
$ docker cp verdaccio:/verdaccio/conf /mydocker/verdaccio/conf
$ docker cp verdaccio:/verdaccio/plugins /mydocker/verdaccio/plugins
$ docker rm -f verdaccio
$ docker run -itd --name verdaccio -p 4873:4873 -v /mydocker/verdaccio/storage:/verdaccio/storage -v /mydocker/verdaccio/conf:/verdaccio/conf -v /mydocker/verdaccio/plugins:/verdaccio/plugins verdaccio/verdaccio
$ docker update verdaccio --restart=always

Chrome 浏览器打开 http://ip:4873,会看到如下管理界面。

verdaccio

Step2:发布npm包到私有库的流程

有了私有库以后,就可以在其上发布 npm 包。但初始化时需要先添加用户,设置用户名和密码等,然后就可以直接发包了。

添加用户:输入如下命令,然后输入用户名、密码和邮箱。

1
$ npm adduser --registry http://ip:4873/

发布npm包:当需要把某个项目发布到私有库时,直接publish。发布成功后,刷新页面,就能看到最新发布的包。

1
$ npm publish --registry http://ip:4873

Step3:安装私有库npm包的流程

在项目目录下增加 .npmrc 文件,指定仓库地址。使用 npm install 包名,即可安装私有包了。

1
registry=http://ip:4873/

8.7 搭建项目管理工具禅道

8.7.1 禅道简介

禅道 是一款国产的开源项目管理软件,它的核心管理思想基于敏捷方法scrum,内置了产品管理和项目管理,同时又根据国内研发现状补充了测试管理、计划管理、发布管理、文档管理、事务管理等功能,在一个软件中就可以将软件研发中的需求、任务、bug、用例、计划、发布等要素有序的跟踪管理起来,完整地覆盖了项目管理的核心流程。

8.7.2 禅道部署

1
2
3
$ docker pull idoop/zentao
$ docker run -d -p 8183:80 -p 8184:3306 -e ADMINER_USER="root" -e ADMINER_PASSWD="password" -e BIND_ADDRESS="false" --name zentao idoop/zentao:latest
$ docker logs -f zentao

启动完成后,打开Chrome访问http://ip:8183地址(默认用户名:admin,密码:123456;数据库用户:root,默认密码:123456)

禅道

8.8 搭建 Nginx Proxy Manager 管理面板

8.8.1 Nginx Proxy Manager 简介

Nginx Proxy Manager门槛极低,操作简单,不需要你掌握很复杂的Nginx配置知识,只需要几步就能很轻松完成反向代理的设置和SSL证书的部署。便捷直观的web页面管理和操作无疑大大简化了一般Nginx反代服务的步骤。

项目地址:https://github.com/jc21/nginx-proxy-manager

8.8.2 Nginx Proxy Manager 部署

Step1:安装 Docker 和 Docker-Compose

Step2:编写配置文件

docker-compose.yml

1
2
3
4
5
6
7
8
9
10
11
12
version: '3'
services:
app:
image: 'jc21/nginx-proxy-manager:latest'
restart: unless-stopped
ports:
- '79:80'
- '81:81'
- '442:443'
volumes:
- ./data:/data
- ./letsencrypt:/etc/letsencrypt

Step3:创建并运行容器

1
$ docker-compose up -d

Step4:浏览器访问面板

使用 Chrome 浏览器访问 http://IP:81 地址,默认账号如下,登录后建议立刻进行修改,之后便可以看到如下面板。

1
2
Email:    [email protected]
Password: changeme

Nginx Proxy Manager面板

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

[85] Linux shell脚本传参,传入数组 from CSDN

[86] docker在容器外执行某个容器内的某个命令 from CSDN

[87] 如何跨容器调用可执行命令 from lyer’s blog

[88] 错误:the input device is not a TTY from CSDN

[89] 如何在Debian 10上安装Anaconda Python发行版 from howtoing运维教程

[90] 10 分钟上手 Vim,常用命令大盘点 from 知乎

[91] 查看docker容器使用的资源 from 博客园

[92] linux 下取进程占用 cpu/内存 最高的前10个进程 from CSDN

[93] 如何在Debian 11上安装Apache Maven from 云东方

[94] curl模拟delete/put/post/get请求 from CSDN

[95] 【Docker】daemon.json的作用(八)from CSDN

[96] 清空docker container logs from 暗无天日

[97] docker 容器日志清理方案 from 简书

[98] rclone 迁移minio数据 from CSDN

[99] 使用 Logstash 同步海量 MySQL 数据到 ES from 腾讯云

[100] 使用logstash 运行配置文件,出现you must change the “path.data” setting from CSDN

[101] Linux下Python程序Killed,分析其原因 from CSDN

[102] 查询CPU、GPU相关信息 from 51CTO博客

[103] 安装elasticsearch-analysis-ik分词器插件 from CSDN

[104] Centos7.5安装java8 from 简书

[105] linux下安装ffmpeg的详细教程 from 腾讯云

[106] Elasticsearch可视化工具 from CSDN

[107] CloudFlare 关闭自适应 IPv6 解析的方法 from 老唐笔记

[108] 实例 IP 地址 ping 不通 from 腾讯云

[109] 使用 docker + verdaccio 搭建私有npm仓库 from 稀土掘金