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 通过KiWiVM管理面板进行数据迁移
  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 放行指定端口及ufw防火墙
      5. 2.2.5 Crontab定时任务与设置开机自启
      6. 2.2.6 jar包部署执行
      7. 2.2.7 文件及目录操作
      8. 2.2.8 查询CPU与GPU详细参数
      9. 2.2.9 磁盘空间及系统资源占用分析
      10. 2.2.10 进程被kill的问题排查
      11. 2.2.11 解决IP无法ping通的问题
      12. 2.2.12 生成随机密钥
      13. 2.2.13 Shell脚本实现进度条
    3. 2.3 原生部署开发环境
      1. 2.3.1 安装jdk与maven环境
      2. 2.3.2 安装python与conda环境
      3. 2.3.3 安装node.js和npm环境
      4. 2.3.4 安装mysql环境
      5. 2.3.5 安装redis环境
      6. 2.3.6 安装nginx环境
      7. 2.3.7 安装go及bee环境
      8. 2.3.8 安装ffmpeg工具
    4. 2.4 vim常用操作
      1. 2.4.1 vim工作模式
      2. 2.4.2 vim常用命令
    5. 2.5 Linux运维脚本
      1. 2.5.1 自动重启挂掉的jar包
      2. 2.5.2 自动重启挂掉的python服务
      3. 2.5.3 jar包运维脚本
      4. 2.5.4 解压zip文件脚本
      5. 2.5.5 将文件传输到其他服务器
    6. 2.6 使用NFS挂载另一台服务器上的目录
  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占用的存储空间
      7. 5.2.7 解决Docker容器时区不正确的问题
    3. 5.3 Docker Compose环境搭建与基本使用
      1. 5.3.1 Docker Compose环境搭建
      2. 5.3.2 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 拉取镜像创建实例容器并运行
      2. 6.1.2 创建数据库及用户
    2. 6.2 Docker-Nginx环境搭建
      1. 6.2.1 拉取镜像创建实例容器并运行
      2. 6.2.2 修改Nginx配置文件
      3. 6.2.3 测试Nginx环境
      4. 6.2.4 搭建过程踩的坑
    3. 6.3 Docker-Oracle环境搭建
      1. 6.3.1 拉取镜像并运行容器
      2. 6.3.2 进入容器进行配置
      3. 6.3.3 修改密码创建用户
      4. 6.3.4 用连接工具登录
    4. 6.4 Docker-MongoDB环境搭建
      1. 6.4.1 拉取镜像并运行容器
      2. 6.4.2 Mongodb创建用户并可视化查看
    5. 6.5 Docker-RabbitMQ环境搭建
      1. 6.5.1 拉取镜像并运行容器
      2. 6.5.2 RabbitMQ创建用户并可视化查看
    6. 6.6 Docker-Kafka环境搭建
      1. 6.6.1 使用Docker Compose部署kafka
      2. 6.6.2 验证kafka是否搭建成功
      3. 6.6.3 搭建kafka管理平台
    7. 6.7 Docker-Redis环境搭建
      1. 6.7.1 拉取镜像并运行容器
      2. 6.7.2 Redis数据库的可视化连接
    8. 6.8 Docker-ElasticSearch环境搭建
      1. 6.8.1 拉取镜像并运行容器
      2. 6.8.2 可视化管理ES
      3. 6.8.3 安装ik分词器插件
      4. 6.8.4 使用curl操作ES
    9. 6.9 Docker-EMQX环境搭建
      1. 6.9.1 拉取镜像并运行容器
      2. 6.9.2 EMQX的管理面板
    10. 6.10 Docker-Minio环境搭建
      1. 6.10.1 拉取镜像并运行容器
      2. 6.10.2 Minio的管理面板
  7. 7. 网站环境搭建
    1. 7.1 使用 acme.sh 申请泛域名SSL证书
      1. 7.1.1 安装 acme.sh 服务
      2. 7.1.2 生成SSL泛域名证书
      3. 7.1.3 acme.sh的一些其他管理命令
    2. 7.2 使用OneinStack搭建Nginx并进行配置
      1. 7.2.1 OneinStack简介
      2. 7.2.2 使用OneinStack搭建Nginx服务
      3. 7.2.3 创建网站开启HTTPS
      4. 7.2.4 配置反向代理
    3. 7.3 网站开启CDN服务
      1. 7.3.1 CDN与Cloudflare是什么
      2. 7.3.2 开启 Cloudflare CDN 服务
      3. 7.3.3 重定向次数过多问题
      4. 7.3.4 CDN缓存问题
      5. 7.3.5 关闭IPv6支持
    4. 7.4 Git Hooks自动部署
      1. 7.4.1 Git Hooks简介
      2. 7.4.2 创建网站并更改权限
      3. 7.4.3 修改Nginx配置
      4. 7.4.4 配置Git Hooks
  8. 8. 开发辅助环境搭建
    1. 8.1 搭建ReverseProxy破解JRebel热部署插件
      1. 8.1.1 在VPS搭建ReverseProxy服务
      2. 8.1.2 配置开机自启、HTTPS及反向代理
    2. 8.2 使用 Rustdesk 远程控制
      1. 8.2.1 Rustdesk 简介
      2. 8.2.2 搭建 rustdesk-server
      3. 8.2.3 客户端配置自建服务器
  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 11 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 通过KiWiVM管理面板进行数据迁移

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

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

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
10
11
12
$ apt-get install -y sudo                                     # 安装sudo
$ sudo apt-get update # 更新apt-get
$ apt-get update && apt-get install iputils-ping -y # 安装ping
$ apt-get install -y wget # 安装wget
$ apt-get update -y && apt-get install curl -y # 安装curl
$ apt-get install xz-utils # 安装xz
$ apt-get install p7zip-full # 安装7z
$ apt-get install zip # 安装zip
$ apt-get install tree # 安装tree
$ apt-get update && apt-get install vim -y # 安装vim
$ apt-get install lsof # 安装lsof
$ apt-get update && apt-get install -y psmisc # 安装ps

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

2.2.2 使用Shell脚本

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

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

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

基本示例:

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

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

[2] Shell脚本遍历数组

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

[3] 打印当前目录

1
echo "$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

2.2.3 查看及修改系统配置

[1] 查看系统发行版

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

[2] 修改系统时间

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

1
2
3
4
$ date -R   // 查看系统时间
$ rm -rf /etc/localtime
$ ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
$ date -R

[3] 扩充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,扩充完毕

[4] 查看系统用户

1
$ cat /etc/passwd | head -5 | cut -f1 -d:

2.2.4 放行指定端口及ufw防火墙

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

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

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.5 Crontab定时任务与设置开机自启

crontab 是 Linux 下的计划任务,当时间达到我们设定的时间时,可以自动触发某些脚本的运行。

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:每分钟执行一次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

Crontab 中有个特殊的任务,叫作 @reboot ,这个任务就是在系统重启之后自动运行某个脚本。

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

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

2.2.6 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 xxx.jar > xxx.log 2>&1 &

注意事项:

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

2.2.7 文件及目录操作

[1] 查看目录结构

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

[2] 统计文件及文件夹个数

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

[3] 查找文件及目录

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

[4] 拷贝同步大量文件

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

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

[5] 远程文件拷贝

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。以上命令在发送方输入,之后会提示输入接收方的服务器连接密码。

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

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

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 命令执行速度更快且更安全。

[7] 生成图片的base64字符串写入文件

1
$ base64 base64_gegerate_test.png > base64.txt

2.2.8 查询CPU与GPU详细参数

[1] 查询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] 查看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.9 磁盘空间及系统资源占用分析

[1] 磁盘空间占用分析

1
2
3
4
5
6
7
8
$ df -hl                      // 查看磁盘剩余空间
$ 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] 系统资源占用分析

1
2
3
4
5
6
7
8
9
10
11
// 查看剩余内存
$ free -m

// 1.CPU占用最多的前10个进程
$ ps auxw|head -1;ps auxw|sort -rn -k3|head -10

// 2.内存消耗最多的前10个进程
$ ps auxw|head -1;ps auxw|sort -rn -k4|head -10

// 3.虚拟内存使用最多的前10个进程
$ ps auxw|head -1;ps auxw|sort -rn -k5|head -10

[3] kill指定端口号的进程

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

[4] 监控进程状态

1
$ ps -aux | grep 进程号

[5] 查看指定行的nohup.out日志

1
$ tail -fn 100 nohup.out

[6] 清理指定时间前的指定类型文件

1
2
3
4
// 清理7天前的pdf文件
$ find /root/tmp -name "*.pdf" -type f -mtime +7 -exec rm -rf {} \; > /dev/null 2>&1
// 清理1分钟前的pdf文件
$ find /root/tmp -name "*.pdf" -type f -mmin +1 -exec rm -rf {} \; > /dev/null 2>&1

2.2.10 进程被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.11 解决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.12 生成随机密钥

1
$ openssl rand -hex 32

2.2.13 Shell脚本实现进度条

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

progress_bar=''
for i in {0..100..2}
do
printf "process:[%-50s]%d%%\r" $progress_bar $i
sleep 0.2
progress_bar=#${progress_bar}
done
echo ""

含义说明:

  • 先定义process_bar为空,后依次加#,递增
  • 0到100之间,每次递增2,所以进度条使用%-50s来显示,其中-代表左对齐。50是字符串宽度
  • %d来显示进度条的i,%%则代表百分号
  • \r回车
  • sleep 0.2每次间隔0.2秒
  • echo “” 起到换行作用

执行效果:

1
process:[##################################################]100%

2.3 原生部署开发环境

常用开发环境的版本号查询:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ java -v
$ javac -v
$ mvn --version
$ python3 -v
$ pip3 -V
$ nginx -v
$ mysql -V
$ redis-server -v
$ nodejs --version
$ npm --version
$ go version
$ docker version
$ docker-compose --version
$ git version
$ curl -XGET localhost:9200 // 查询ES

2.3.1 安装jdk与maven环境

以下分别介绍Open JDK 11、Open JDK 8、Oracle JDK8的安装及配置过程,Maven的配置与JDK的配置有关

jdk11(Open JDK 11)

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

jdk8(Open JDK 8)

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

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

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

1
2
$ java -version
$ javac -version

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

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

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

jdk8(Oracle JDK8)

Oracle官网 或者 第三方网站 下载JDK安装包,将其与安装脚本放置到同一个目录下,授予脚本可执行权限然后执行脚本即可。

例如:jdk-8u202-linux-x64.tar.gz

1
$ wget https://mirrors.huaweicloud.com/java/jdk/8u202-b08/jdk-8u202-linux-x64.tar.gz

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

# 请将下载的jdk-xxx-linux-xxx.tar.gz包与此脚本放置到同一目录
# 授予此脚本可执行权限(chmod +x install_jdk.sh)
# 安装完毕后,如果测试命令不好使,再次执行 source /etc/profile 命令即可。

# 检查jvmpath路径
jvmpath=/usr/lib/jvm/

if [ ! -d "$jvmpath" ]; then
echo "正在创建$jvmpath目录"
mkdir $jvmpath
echo "目录$jvmpath创建成功"
fi

jdkfile=$(ls | grep jdk-*-linux-*.tar.gz)


if [ -f "$jdkfile" ]; then

# 解压jdk安装包
tar -zxvf $jdkfile -C $jvmpath
echo "解压JDK成功"

# 配置环境变量
echo "配置环境变量"
jdkdirname=$(ls $jvmpath)
cp /etc/profile /etc/profile.bak
echo "JAVA_HOME=$jvmpath/$jdkdirname" >> /etc/profile
echo "JRE_HOME=\${JAVA_HOME}/jre" >> /etc/profile
echo "CLASSPATH=.:\${JAVA_HOME}/lib:\${JRE_HOME}/lib" >> /etc/profile
echo "PATH=\$PATH:\${JAVA_HOME}/bin:\${JRE_HOME}/bin" >> /etc/profile
source /etc/profile
echo "配置环境成功"

# 检查是否配置成功
echo "测试是否安装成功"
java -version
javac -version

fi

另附:CentOS7系统安装openjdk8

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ 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

如果出现 Error downloading packages: fribidi-1.0.2-1.el7_7.1.x86_64: [Errno 256] No more mirrors to try. 错误,输入如下命令再重试。
$ yum --enablerepo=base clean metadata

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.3.2 安装python与conda环境

[1] 将Python升级为3.x

Debian10 预装的 python 是 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] 安装conda与pip环境

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

1
2
3
4
5
6
7
8
$ 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 // 查询所有虚拟环境
$ conda remove -n conda_env --all // 删除虚拟环境

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.3.3 安装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.3.4 安装mysql环境

授予脚本可执行权限然后执行脚本即可。

install_mysql.sh

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#!/bin/bash

# 下载deb安装包
wget https://dev.mysql.com/get/Downloads/MySQL-5.7/mysql-server_5.7.31-1ubuntu18.04_amd64.deb-bundle.tar
# 新建目录
mkdir mysql5.7.31
mv mysql-server_5.7.31-1ubuntu18.04_amd64.deb-bundle.tar ./mysql5.7.31
# 解压
cd mysql5.7.31
sudo tar -vxf mysql-server_5.7.31-1ubuntu18.04_amd64.deb-bundle.tar
# 删除2个测试相关的包
sudo rm -f mysql-testsuite_5.7.31-1ubuntu18.04_amd64.deb
sudo rm -f mysql-community-test_5.7.31-1ubuntu18.04_amd64.deb
# 安装依赖
sudo apt-get install libtinfo5
sudo apt-get install libmecab2
# 使用deb安装
sudo dpkg -i mysql-*.deb
# 启动mysql
sudo service mysql start
# 查看mysql状态
sudo service mysql status

常用命令如下:

1
2
3
4
$ sudo service mysql start       // 启动mysql
$ sudo service mysql stop // 停止mysql
$ sudo service mysql restart // 重启mysql
$ sudo service mysql status // 查看mysql状态

2.3.5 安装redis环境

授予脚本可执行权限然后执行脚本即可。

install_redis.sh

1
2
3
4
5
#!/bin/bash

sudo apt-get update
sudo apt-get install redis-server
redis-server /etc/redis.conf # 使用配置文件启动,守护进程

验证是否启动成功

1
2
3
4
5
6
7
$ redis-cli
127.0.0.1:6379> ping
PONG // 返回PONG即为启动成功
127.0.0.1:6379> shutdown // 关闭Redis服务
not connected> ping
Could not connect to Redis at 127.0.0.1:6379: Connection refused // 服务已经关闭
not connected>

Redis默认是没有密码的(仅能本机访问),如果要设置密码,并放行外网访问,请修改/etc/redis/redis.conf的配置,修改后重启Redis服务。

1
2
3
4
5
6
7
8
9
$ vim /etc/redis/redis.conf

# 1.设置访问密码(放开requirepass的注释并将foobared修改成你要的密码,如:123456)
# requirepass foobared
requirepass 123456
# 2.放通外网访问(注释掉redis.conf中的bind)
# bind 127.0.0.1 ::1

$ /etc/init.d/redis-server restart

常用命令如下:

1
2
3
/etc/init.d/redis-server restart    # 重启服务
/etc/init.d/redis-server start # 启动服务
/etc/init.d/redis-server stop # 停止服务

2.3.6 安装nginx环境

授予脚本可执行权限然后执行脚本即可。

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

## 依赖安装
# 安装gcc g++依赖库
sudo apt-get install build-essential
sudo apt-get install libtool
# 安装pcre依赖库
sudo apt-get update
sudo apt-get install libpcre3 libpcre3-dev
# 安装zlib依赖库
sudo apt-get install zlib1g-dev
# 安装SSL依赖库
sudo apt-get install openssl

## Nginx安装
# 下载安装包
wget http://nginx.org/download/nginx-1.20.1.tar.gz
# 解压
tar -zxvf nginx-1.20.1.tar.gz
# 进入解压目录
cd nginx-1.20.1
# 配置
./configure --prefix=/usr/local/nginx
# 编译并且安装:
make && make install
# 进入sbin目录启动
cd /usr/local/nginx/sbin
./nginx

常用nginx命令:

1
2
3
$ service nginx start
$ nginx -t
$ nginx -s reload

2.3.7 安装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.3.8 安装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.4 vim常用操作

2.4.1 vim工作模式

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

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

2.4.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.5 Linux运维脚本

2.5.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.5.2 自动重启挂掉的python服务

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

while true
do
monitor=`ps -ef | grep server.py | grep -v grep | wc -l`
if [ $monitor -eq 0 ]
then
echo "server.py is not running, restart server.py"
nohup python server.py > server.log 2>&1 &
else
echo "server.py is running"
fi
sleep 5
done

2.5.3 jar包运维脚本

可以把springboot项目打包出的jar包通过运维脚本来管理。

脚本1: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: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
#!/bin/bash

#define default variable
app_path=$(cd `dirname $0`; pwd)
app_log="${app_path}/app.log"
port=8080

if [ -e $app_log ]; then
touch ${app_log}
fi

#goto directory
cd ${app_path}

#kill app process
lsof -i :${port}|grep -v "PID"|awk '{print "kill -9",$2}'|sh

#clear log
cat /dev/null>${app_log}

#start app
chmod 777 * -R
nohup java -jar *.jar 1>${app_log} &
tail -fn 100 ${app_log}
exit 0

2.5.4 解压zip文件脚本

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

#define default variable
base_path=$(cd `dirname $0`; pwd)
app_path="${base_path}/dist"
zip_name="${base_path}/dist.zip"
chmod 777 ${zip_name}
rm -fr ${app_path}
unzip -d ${app_path} ${zip_name}
echo "unzip success!"

2.5.5 将文件传输到其他服务器

sshpass是为了解决scp命令需要输入密码的问题,只需要在发送方安装,可在线安装也可离线安装。

1
$ apt-get install sshpass

sshpass.sh

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#!/bin/sh

# 定义scp参数
source_dir=/root/source/
target_dir=/root/target/
host=目标服务器IP
port=目标服务器端口
username=目标服务器用户名
password=目标服务器密码

# 将本机某目录下的所有文件拷贝到另一台服务器的指定目录
time=$(date "+%Y-%m-%d %H:%M:%S")
echo "===$time task start===" >> scp.log
for filename in $(ls $source_dir)
do
# 传输文件
echo "sshpass -p $password scp -P $port $source_dir$filename [email protected]$host:$target_dir" >> scp.log
sshpass -p $password scp -r -P $port $source_dir$filename [email protected]$host:$target_dir
# 删除文件
echo "rm -f $source_dir$filename" >> scp.log
rm -f $source_dir$filename
done
echo "===$time task end===" >> scp.log

2.6 使用NFS挂载另一台服务器上的目录

NFS(network file system)网络文件系统工具,通过网络使不同机器或者操作系统之间分享部分文件,用于宿主机和目标机之间的文件共享。使用该方式需要管理员权限,服务端配置好后,客户端不需要认证登录就可以挂载。

测试服务器示例:

1
2
文件服务器(被挂载机):192.168.1.100    // 实际存储文件的地方
操作服务器(挂载机):192.168.1.200 // 使用文件的地方(实际不存储在这里)

Step1:安装 NFS(两台机器都需要安装)并设置开机自启

1
2
3
$ sudo apt-get install nfs-kernel-server -y     // 安装 NFS 服务
$ systemctl status nfs-kernel-server.service // 查看NFS服务是否启动
$ systemctl enable nfs-kernel-server.service // 设置NFS主程序开机启动

Step2:在文件服务器(被挂载机)上新建目录,配置权限,配置挂载

1
2
$ mkdir -p /nfs_mount/.nfs_do_not_delete && chmod 777 -R /nfs_mount/.nfs_do_not_delete
$ vim /etc/exports

编辑需要共享的目录和允许访问的服务器(*为不限制IP,不建议这么做,但如果不想限制IP就把如下配置的192.168.1.200换成*即可)及权限,内容如下:

1
/nfs_mount/.nfs_do_not_delete 192.168.1.200(rw,sync,no_root_squash)    

注:如果服务器的端口大于1024,则还需要加上insecure,如果未加 insecure,下一步挂载时会报错mount.nfs: access denied by server while mounting

1
/nfs_mount/.nfs_do_not_delete 192.168.1.200(insecure,rw,sync,no_root_squash)  

重启文件服务器(被挂载机)NFS服务。

1
$ sudo /etc/init.d/nfs-kernel-server restart

另注:如果挂载后创建文件出现mount.nfs: Read-only file system的错误,是/etc/exports的配置有问题(例如IP与权限的那个括号之间应该没有空格,请查看是不是加了空格导致的)。

Step3:操作服务器(挂载机)新建目录,配置挂载

1
2
3
4
5
$ mkdir /storage
$ sudo mount 192.168.1.100:/nfs_mount/.nfs_do_not_delete /storage/
$ mount // 显示当前系统已经挂载的设备及挂载点
$ cd /storage && touch test.txt // 创建测试文件,去文件服务器(被挂载机)查看文件是否存在
$ cd /storage && rm -f test.txt // 删除测试文件

使用 umount 卸载挂载

1
$ sudo umount 192.168.1.100:/nfs_mount/.nfs_do_not_delete /storage

注意:如果出现 umount.nfs: XXX: device is busy 错误,可使用以下方式强制卸载挂载

1
2
3
$ sudo fuser –m –v /storage
$ kill -9 [pid]
$ sudo umount –lf 192.168.1.100:/nfs_mount/.nfs_do_not_delete /storage

Step4:设置开机自动挂载

1
2
$ vim /etc/rc.local  // 写入如下配置
sudo mount 192.168.1.100:/nfs_mount/.nfs_do_not_delete /storage/

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 客户端 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的架构

我们通过给 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 命令来启动并运行整个应用程序。

![Docker Compose组成](https://image.eula.club/hexo/Docker Compose组成.png)

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镜像的版本号

[18] 设置开机自启与取消开机自启

1
2
$ docker update --restart=always [CONTAINER ID/NAMES]  // 设置开机自启
$ docker update --restart=no [CONTAINER ID/NAMES] // 取消开机自启

[19] docker network相关命令

默认docker之间的网络不互通,如果需要其互相连接,则需要配置docker network。

1
2
3
4
5
6
$ docker network create [network_name]    // 创建网络
$ docker network ls // 查看已创建的网络列表
$ docker network inspect [network_name] // 查看具体的网络详情
$ docker network connect [network_name] [CONTAINER ID/NAMES] // 将容器加入网络,或者 docker run 时加 --network 进行指定
$ docker network disconnect [network_name] [CONTAINER ID/NAMES] // 将容器移除网络
$ docker network rm [network_name] // 删除具体的网络

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.2.7 解决Docker容器时区不正确的问题

[1] 修改已运行容器的时区

Step1:进入需要更改时区的容器

1
$ docker exec -it <容器> /bin/bash

Step2:将宿主机的时区链接到容器里

1
$ ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime

Step3:退出并重启容器

1
2
$ exit
$ docker restart <容器>

[2] 在docker run命令中修改时区

运行容器时,加上挂载参数

1
$ docker run -d <容器> -v /etc/timezone:/etc/timezone -v /etc/localtime:/etc/localtime

或者通过-e TZ=”Asia/Shanghai”设置时区:

1
$ docker run -d <容器> -e TZ="Asia/Shanghai"

[3] 在Dockerfile中修改时区

在Dockerfile中

1
2
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
RUN echo 'Asia/Shanghai' > /etc/timezone

[4] 在Compose中修改时区

在docker-compose.yml文件中

1
2
3
volumes:
- /etc/timezone:/etc/timezone
- /etc/localtime:/etc/localtime

5.3 Docker Compose环境搭建与基本使用

5.3.1 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.3.2 Docker Compose基本使用

首先要编写好docker-compose.yml文件,然后构建镜像、运行容器即可。

1
2
3
$ cd /docker-compose-path  // 切换到docker-compose.yml文件所在的目录
$ docker-compose build // 构建镜像
$ docker-compose up -d // 运行容器

5.4 通过Dockerfile自动构建镜像

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

Dockerfile语法

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

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

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

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

5.4.1 使用Docker部署Springboot项目

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

1
2
3
4
5
6
7
8
9
10
# 基于java8镜像创建新镜像
FROM java:8
# 作者
MAINTAINER eula
# 将jar包添加到容器中并更名为app.jar
COPY test-project-0.0.1-SNAPSHOT.jar /app.jar
# 安装vim命令
RUN apt-get update && apt-get install vim -y
# 后台运行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 -e TZ="Asia/Shanghai" 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
# 基于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
# 启动项目
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 -e TZ="Asia/Shanghai" test-flask-image:latest // 通过镜像运行容器
$ docker update test-flask --restart=always // 设置开机自启

5.4.3 使用Docker部署前端项目

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

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

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

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

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

注:容器内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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
$ docker network create yoyo

$ docker run -itd --name yoyo_mysql -h yoyo_mysql --network yoyo -p 3306:3306 \
-e TZ=Asia/Shanghai \
-v /root/docker/mysql/conf:/etc/mysql/conf.d \
-v /root/docker/mysql/logs:/var/log/mysql \
-v /root/docker/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 -p 6379:6379 redis:3.2.8 --requirepass "mypassword"
$ docker update yoyo_redis --restart=always

$ docker run -itd --name yoyo_es -h yoyo_es --network yoyo -p 9200:9200 \
-e "discovery.type=single-node" \
-e ES_JAVA_OPTS="-Xms512m -Xmx512m" \
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

注:可使用 docker network ls 命令查看已创建的网络,创建容器时需要使用–network 指定网络,建议用 -h 指定 hostname,除 emqx 的1883端口外,其他服务可不使用 -p 对外映射端口号,我这里为了调试方便,仍然把不必要的端口暴露出来了。

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

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

前端项目打包(以 Angular 为例)

1
2
3
$ npm install -g @angular/cli   
$ npm install
$ ng build --base-href ./

后端项目打包(以Springboot为例)

1
2
3
$ mvn clean
$ mvn install
$ mvn package

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

Step3:准备项目部署所需要的配置文件及脚本

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
.
├── config
├── application-prod.properties
└── application.properties
├── dist.zip
├── Dockerfile
├── nginx.conf
├── proxy.conf
├── yoyo_web.conf
├── web_manage-0.0.1.jar
├── unzip.sh
├── build.sh
├── rebuild.sh
└── start_web_manage.sh

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

nginx.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
user  root;
worker_processes auto;

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


events {
worker_connections 1024;
}


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

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

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

sendfile on;
#tcp_nopush on;

keepalive_timeout 65;

#gzip on;

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

yoyo_web.conf(需要修改后端的接口地址和前端文件的存放路径,location ~* ^这里根据实际项目的路由配置进行转发)

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:8081 weight=1 max_fails=1 fail_timeout=10s;
}
server {
listen 82;
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 /storage/web_code;
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;

[2] 准备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
29
30
31
32
33
34
35
36
37
38
39
40
# 设置基础镜像
FROM nginx

# 安装常用命令
RUN apt-get update
RUN apt-get install -y wget # 安装wget
RUN apt-get install vim -y # 安装vim
RUN apt-get install -y psmisc # 安装ps

# 设置工作目录
RUN mkdir /storage
WORKDIR /storage

# 安装java8环境
RUN mkdir /usr/local/java
# 方式一:下载jdk并解压到指定目录(适用于网速快的情况,需要提前安装wget)
RUN wget https://mirrors.huaweicloud.com/java/jdk/8u202-b08/jdk-8u202-linux-x64.tar.gz
RUN tar zxvf jdk-8u202-linux-x64.tar.gz -C /usr/local/java && rm -f jdk-8u202-linux-x64.tar.gz
# 方式二:将本地jdk复制到内部目录并自动解压(适用于网速慢的情况,提前下载好)
# ADD jdk-8u202-linux-x64.tar.gz /usr/local/java
# RUN rm -f jdk-8u202-linux-x64.tar.gz
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/ /storage/web_code
COPY nginx.conf /etc/nginx/nginx.conf
COPY yoyo_web.conf /etc/nginx/conf.d/yoyo_web.conf
COPY proxy.conf /etc/nginx

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

# 放置启动脚本并授予权限
COPY start_web_manage.sh /storage/start_web_manage.sh
RUN chmod u+x /storage/start_web_manage.sh

注:前端包我这里采用的是将 zip 通过shell脚本解压后再拷贝进容器的方式,如果采用 tar.gz 格式,ADD命令会自动对其进行解压(其他压缩格式不可以)。

1
ADD dist.tar.gz /storage/web_code

[3] 准备部署脚本

unzip.sh(无需修改)

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

#define default variable
base_path=$(cd `dirname $0`; pwd)
app_path="${base_path}/dist"
zip_name="${base_path}/dist.zip"
rm -fr ${app_path}
unzip -d ${app_path} ${zip_name}
echo "unzip success!"

build.sh(可不修改,也可根据实际需要修改)

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

base_path=$(cd `dirname $0`; pwd)
uploads_path="${base_path}/uploads"
mkdir ${uploads_path}
chmod u+x ${base_path}/unzip.sh
${base_path}/unzip.sh
docker build -t 'yoyo_web_image' .
docker run -itd --name yoyo_web -h yoyo_web --network yoyo -v ${uploads_path}:/usr/share/nginx/html/uploads -p 8082:82 -p 8081:8081 -e TZ="Asia/Shanghai" yoyo_web_image
docker exec -itd `docker ps |grep yoyo_web |awk '{print $1}'` /bin/bash -c 'java -jar -Duser.timezone=GMT+8 /storage/web_manage-0.0.1.jar > /storage/web_manage-0.0.1.log 2>&1'
docker exec -it `docker ps |grep yoyo_web |awk '{print $1}'` /bin/bash -c 'tail -fn 100 /storage/web_manage-0.0.1.log'

rebuild.sh(可不修改,也可根据实际需要修改)

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

docker rm -f yoyo_web
docker rmi -f yoyo_web_image
base_path=$(cd `dirname $0`; pwd)
uploads_path="${base_path}/uploads"
mkdir ${uploads_path}
chmod u+x ${base_path}/unzip.sh
${base_path}/unzip.sh
docker build -t 'yoyo_web_image' .
docker run -itd --name yoyo_web -h yoyo_web --network yoyo -v ${uploads_path}:/usr/share/nginx/html/uploads -p 8082:82 -p 8081:8081 -e TZ="Asia/Shanghai" yoyo_web_image
docker exec -itd `docker ps |grep yoyo_web |awk '{print $1}'` /bin/bash -c 'java -jar -Duser.timezone=GMT+8 /storage/web_manage-0.0.1.jar > /storage/web_manage-0.0.1.log 2>&1'
docker exec -it `docker ps |grep yoyo_web |awk '{print $1}'` /bin/bash -c 'tail -fn 100 /storage/web_manage-0.0.1.log'

start_web_manage.sh(可不修改,也可根据实际需要修改)

1
nohup java -jar -Duser.timezone=GMT+8 /storage/web_manage-0.0.1.jar > /storage/web_manage-0.0.1.log 2>&1 &

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

1)初次部署

1
2
3
切换到工作目录
$ chmod u+x unzip.sh build.sh rebuild.sh
$ ./build.sh

启动成功后,项目就部署好了,Chrome访问 IP:8082地址即可访问前端页面,8081端口是留给后端的。

2)后续更新

1
2
切换到工作目录
把 dist.zip 和 web_manage-0.0.1.jar 更换掉,然后执行 rebuild.sh 脚本即可

3)启动项目

build.sh及rebuild.sh脚本已经设置了自启动,默认初次部署不需要手动启动(如果容器重启过了,就需要手动启动项目)

1
2
3
4
5
// 方式一:容器外
$ docker exec -itd `docker ps |grep yoyo_web |awk '{print $1}'` /bin/bash -c 'java -jar -Duser.timezone=GMT+8 /storage/web_manage-0.0.1.jar > /storage/web_manage-0.0.1.log 2>&1'

// 方式二:容器内
$ cd /storage && ./start_web_manage.sh

注意事项:docker exec -itd 这里必须带上d,让容器后台启动,类似shell脚本中的&,如果没有会导致容器启动后自动退出。带上d之后,后面的shell命令不要加nohup。

4)日志查看

1
2
3
4
5
// 方式一:容器外
$ docker exec -it `docker ps |grep yoyo_web |awk '{print $1}'` /bin/bash -c 'tail -fn 100 /storage/web_manage-0.0.1.log'

// 方式二:容器内
$ tail -fn 100 /storage/web_manage-0.0.1.log

注意事项:docker exec -it 这里必须不带上d,否则看不到输出结果。

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 拉取镜像创建实例容器并运行

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 /root/docker/mysql/conf:/etc/mysql/conf.d \
-v /root/docker/mysql/logs:/var/log/mysql \
-v /root/docker/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.2 创建数据库及用户

在本地使用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.2 Docker-Nginx环境搭建

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

1
2
$ docker pull nginx
$ docker run -d --name nginx -p 9999:80 nginx:latest

6.2.2 修改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的挂载目录保持一致,也使用了自己创建的/root/docker目录(一般放在/mnt目录,这个是Linux专门的挂载目录)

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

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

1
2
3
$ cd /root/docker/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 /root/docker/nginx/nginx.conf:/etc/nginx/nginx.conf -v /root/docker/nginx/logs:/var/log/nginx -v /root/docker/nginx/html:/usr/share/nginx/html -v /root/docker/nginx/conf:/etc/nginx/conf.d --privileged=true [image-id]

命令解释说明:

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

Step4:设置开机自启

1
$ docker update nginx --restart=always

6.2.3 测试Nginx环境

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

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

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

附:Nginx的常用管理命令

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

6.2.4 搭建过程踩的坑

[1] 非安全端口问题

情景描述:搭建完的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浏览器的默认非安全端口即可。

[2] 访问资源403问题

情景描述:部署的项目有上传文件功能,上传成功后要在网页上进行显示,但该资源却403无权限访问,改目录权限777虽然可以临时使其可以访问,但后续上传的文件又权限不足

错误原因:启动nginx的用户没有该资源的访问权限

解决办法:修改nginx的启动用户为root,访问权限就有了。

1
$ vim /etc/nginx/nginx.conf    // 把第一行的用户配置改成“user  root;”

6.3 Docker-Oracle环境搭建

6.3.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.3.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.3.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.3.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.4 Docker-MongoDB环境搭建

6.4.1 拉取镜像并运行容器

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

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

6.4.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工具连接即可(验证数据库那栏空着就行)

6.5 Docker-RabbitMQ环境搭建

6.5.1 拉取镜像并运行容器

1
2
$ docker pull rabbitmq:3.8-management
$ docker run --name rabbitmq -d -p 15672:15672 -p 5672:5672 rabbitmq:3.8-management

注:默认RabbitMQ镜像是不带web端管理插件的,所以指定了镜像tag为3.8-management,表示下载包含web管理插件版本镜像。

6.5.2 RabbitMQ创建用户并可视化查看

用Chrome访问http://ip:15672即可访问RabbitMQ的Web端管理界面,默认用户名和密码都是guest,出现如下界面代表已经成功了。

RabbitMQ

默认的 guest 账户有访问限制,只能通过本地网络访问,远程网络访问受限,所以在使用时我们一般另外添加用户。

1
2
3
4
5
6
$ docker exec -i -t rabbitmq  bin/bash  
$ rabbitmqctl add_user root 123456 // 添加用户(实际密码设置复杂一些)
$ rabbitmqctl set_permissions -p / root ".*" ".*" ".*" // 赋予root用户所有权限
$ rabbitmqctl set_user_tags root administrator // 赋予root用户administrator角色
$ rabbitmqctl list_users // 查看所有用户即可看到root用户已经添加成功
$ exit

6.6 Docker-Kafka环境搭建

6.6.1 使用Docker Compose部署kafka

搭建Docker Compose环境见本文5.3节

kafka的运行依赖于zookeeper,因而编写zookeeper与kafka的编排文件docker-compose.yml内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
version: '3.2'
services:
zookeeper:
image: wurstmeister/zookeeper
container_name: zookeeper
ports:
- "2181:2181"
restart: always
kafka:
image: wurstmeister/kafka
container_name: kafka
ports:
- "9092:9092"
environment:
- KAFKA_ZOOKEEPER_CONNECT=zookeeper:2181
- KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://IP:9092
- KAFKA_LISTENERS=PLAINTEXT://:9092
volumes:
- ./docker.sock:/var/run/docker.sock
restart: always

注:KAFKA_ADVERTISED_LISTENERS 填写为 PLAINTEXT://IP:9092,这里的 IP 填写成你的公网 IP,如果没带上这个的话,PC是无法连接到服务器上的 kafka 服务的。这里搭建的 kafka 服务仅用于测试,没有设置用户名及密码,勿用于公网生产环境。

编写完毕后,在该文件下的目录下依次执行下面两条命令即可构建好zookeeper和kafka容器:

1
2
$ docker-compose build     // 构建镜像
$ docker-compose up -d // 运行容器

6.6.2 验证kafka是否搭建成功

进入到kafka容器中 并创建topic生产者,执行如下命令:

1
2
3
4
$ docker exec -it kafka /bin/bash
$ cd /opt/kafka_2.13-2.8.1/bin/
$ ./kafka-topics.sh --create --zookeeper zookeeper:2181 --replication-factor 1 --partitions 8 --topic test
$ ./kafka-console-producer.sh --broker-list localhost:9092 --topic test

执行上述命令后,另起一个窗口,执行如下命令,创建kafka消费者消费消息。

1
2
3
$ docker exec -it kafka /bin/bash
$ cd /opt/kafka_2.13-2.8.1/bin/
$ ./kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic test --from-beginning

执行完上诉命令后,在生产者窗口中输入任意内容回车,即可在消费者的窗口查看到消息。

注:kafka_2.13-2.8.1的含义为,2.13是Scala版本,2.8.1是Kafka版本。

6.6.3 搭建kafka管理平台

kafka-manager是目前最受欢迎的kafka集群管理工具,最早由雅虎开源,用户可以在Web界面执行一些简单的集群管理操作。

1
2
$ docker pull sheepkiller/kafka-manager
$ docker run --name kafka-manager -itd -p 9000:9000 -e ZK_HOSTS="IP:2181" --net=host sheepkiller/kafka-manager // 把IP处换成你的服务器IP地址

用Chrome访问http://ip:9000即可访问kafka的Web端管理界面

kafka管理面板-1

连接kafka:点击Cluster,选择Add Cluster,填写Cluster Name(随便起)、Cluster Zookeeper Hosts(zookeeper地址)保存即可。

kafka管理面板-2

6.7 Docker-Redis环境搭建

6.7.1 拉取镜像并运行容器

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

6.7.2 Redis数据库的可视化连接

建议使用 AnotherRedisDesktopManager 开源工具进行可视化连接和管理。

ARDM工具

6.8 Docker-ElasticSearch环境搭建

6.8.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 /root/docker/es/data:/usr/share/elasticsearch/data \
-v /root/docker/es/config:/usr/share/elasticsearch/config \
-v /root/docker/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

进入容器进行配置

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

注意事项

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.8.2 可视化管理ES

使用Elasticvue浏览器插件

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

elasticvue

安装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 /root/docker/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.8.3 安装ik分词器插件

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

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

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

测试方式:ik分词器有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.8.4 使用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.9 Docker-EMQX环境搭建

6.9.1 拉取镜像并运行容器

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

6.9.2 EMQX的管理面板

搭建完后用浏览器访问 http://IP:18083/地址,默认账号及密码为:admin / public,登录后建议立刻修改密码。

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

6.10 Docker-Minio环境搭建

6.10.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.10.2 Minio的管理面板

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

minio-console

7. 网站环境搭建

7.1 使用 acme.sh 申请泛域名SSL证书

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.2 使用OneinStack搭建Nginx并进行配置

7.2.1 OneinStack简介

项目简介:OneinStack是一套部署开发环境的脚本工具,它的部署方式是纯原生部署,我主要使用里面的Nginx,用来辅助生成配置。

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

7.2.2 使用OneinStack搭建Nginx服务

1
$ wget -c http://mirrors.linuxeye.com/oneinstack-full.tar.gz && tar xzf oneinstack-full.tar.gz && ./oneinstack/install.sh --nginx_optio

注:OneinStack采用编译安装的方式搭建Nginx服务,速度比较慢,请耐心等待,常用的默认目录有:

1
2
3
Nginx安装目录: /usr/local/nginx
Nginx配置目录:/usr/local/nginx/conf
网站数据目录:/data/wwwroot/域名

7.2.3 创建网站开启HTTPS

OneinStack 内置了 acme.sh,它会自动帮你申请 SSL 证书。

1
2
$ cd ./oneinstack
$ ./vhost.sh

配置过程的参考示例如下(示例域名为www.demo.com):

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
#######################################################################
# OneinStack for CentOS/RedHat 7+ Debian 8+ and Ubuntu 16+ #
# For more information please visit https://oneinstack.com #
#######################################################################

What Are You Doing?
1. Use HTTP Only
2. Use your own SSL Certificate and Key
3. Use Let's Encrypt to Create SSL Certificate and Key
q. Exit
Please input the correct option: 2 【选择2】

Please input domain(example: www.example.com): www.demo.com 【输入域名】
domain=www.demo.com

Please input the directory for the domain:www.demo.com :
(Default directory: /data/wwwroot/www.demo.com): 【回车,使用默认配置】
Virtual Host Directory=/data/wwwroot/www.demo.com

Create Virtul Host directory......
set permissions of Virtual Host directory......

Do you want to add more domain name? [y/n]: n 【输入n,不添加其他域名了】

Do you want to redirect all HTTP requests to HTTPS? [y/n]: y 【输入y,强制HTTPS】

You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.

Country Name (2 letter code) [CN]: 【回车】

State or Province Name (full name) [Shanghai]: 【回车】

Locality Name (eg, city) [Shanghai]: 【回车】

Organization Name (eg, company) [Example Inc.]: 【回车】

Organizational Unit Name (eg, section) [IT Dept.]: 【回车】

Do you want to add hotlink protection? [y/n]: n 【输入n,不需要防盗链保护】

Allow Rewrite rule? [y/n]: y 【输入y,允许重写规则】

Please input the rewrite of programme :
wordpress,opencart,magento2,drupal,joomla,codeigniter,laravel
thinkphp,pathinfo,discuz,typecho,ecshop,nextcloud,zblog,whmcs rewrite was exist.
(Default rewrite: other): 【回车】
You choose rewrite=other

Allow Nginx/Tengine/OpenResty access_log? [y/n]: y 【输入y,允许日志记录】
You access log file=/data/wwwlogs/www.demo.com_nginx.log

#######################################################################
# OneinStack for CentOS/RedHat 7+ Debian 8+ and Ubuntu 16+ #
# For more information please visit https://oneinstack.com #
#######################################################################
Your domain: www.demo.com
Virtualhost conf: /usr/local/nginx/conf/vhost/www.demo.com.conf
Directory of: /data/wwwroot/www.demo.com
Rewrite rule: /usr/local/nginx/conf/rewrite/other.conf
Self-signed SSL Certificate: /usr/local/nginx/conf/ssl/www.demo.com.crt
SSL Private Key: /usr/local/nginx/conf/ssl/www.demo.com.key
SSL CSR File: /usr/local/nginx/conf/ssl/www.demo.com.csr

配置完成后,修改一下配置文件

1
$ vim /usr/local/nginx/conf/vhost/www.demo.com.conf

server模块删除内容:

1
2
3
4
5
6
7
8
9
10
location ~ [^/]\.php(/|$) {
#fastcgi_pass remote_php_ip:9000;
fastcgi_pass unix:/dev/shm/php-cgi.sock;
fastcgi_index index.php;
include fastcgi.conf;
}

location /.well-known {
allow all;
}

server模块新增内容:

1
2
3
4
5
location ^~ /.well-known/acme-challenge/ {
default_type "text/plain";
allow all;
root /data/wwwroot/www.demo.com/; # 把路径换一下
}

检查并重载Nginx配置

1
2
$ nginx -t
$ nginx -s reload

注:使用nginx -t 命令可以检查Nginx配置,若出现如下内容则说明配置正确。

1
2
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful

之后把资源文件放置到 /data/wwwroot/www.demo.com 目录即可,打开Chrome浏览器即可访问(如果出现403则需要给这个目录添加一下权限)。

7.2.4 配置反向代理

如果需要配置反向代理的话(比如Docker部署的服务),流程同上,只是修改Nginx配置文件处有所不同。

server模块删除内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
location ~ [^/]\.php(/|$) {
#fastcgi_pass remote_php_ip:9000;
fastcgi_pass unix:/dev/shm/php-cgi.sock;
fastcgi_index index.php;
include fastcgi.conf;
}
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf|flv|mp4|ico)$ {
expires 30d;
access_log off;
}
location ~ .*\.(js|css)?$ {
expires 7d;
access_log off;
}
location /.well-known {
allow all;
}

server模块新增内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
location / {
proxy_set_header HOST $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://demo; # 与下面 upstream 的名称一致即可
}
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf|flv|mp4|ico)$ {
proxy_pass http://demo; # 与下面 upstream 的名称一致即可
expires 30d;
access_log off;
}
location ~ .*\.(js|css)?$ {
proxy_pass http://demo; # 与下面 upstream 的名称一致即可
expires 7d;
access_log off;
}
location ^~ /.well-known/acme-challenge/ {
default_type "text/plain";
allow all;
root /data/wwwroot/www.demo.com/; # 把路径换一下
}

与server模块同级新增内容:

1
2
3
upstream demo {
server 127.0.0.1:8888; # 8888换成自己的反向代理端口号
}

7.3 网站开启CDN服务

7.3.1 CDN与Cloudflare是什么

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

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

Cloudflare-CDN

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

7.3.2 开启 Cloudflare CDN 服务

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

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

开启Cloudflare-CDN

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

修改域名服务器地址
1
2
dawn.ns.cloudflare.com
plato.ns.cloudflare.com

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

NameSilo修改域名服务器

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

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

Cloudflare-CDN功能

7.3.3 重定向次数过多问题

问题描述:域名配置了 Cloudflare CDN 服务,给部署的服务用Nginx配置了反向代理,访问页面却出现重定向次数过多问题。

重定向次数过多问题

问题原因:开启SSL证书后选择灵活SSL,由于灵活的SSL强制通过未加密的HTTP连接到源Web服务器,然而web服务器只能以https的方式进行访问,结果http就被拒之门外了。

解决方法:对于采用cloudflare提供的CDN加速来说,将灵活SSL切换到完全的SSL即可解决问题。

完全的SSL

7.3.4 CDN缓存问题

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

Cloudflare-CDN的开发模式

7.3.5 关闭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.4 Git Hooks自动部署

7.4.1 Git Hooks简介

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

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

7.4.2 创建网站并更改权限

使用Nginx创建网站,修改网站根目录的用户组权限为git:git

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

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

1
$ ls -l 网站根目录

7.4.3 修改Nginx配置

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

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")

ReverseProxy

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

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

使用 crontab 计划任务配置开机自启,使用Nginx配置反向代理并开启HTTPS,在Jrebel的激活URL处填写:https://domain.com/{GUID}即可成功激活。

8.2 使用 Rustdesk 远程控制

8.2.1 Rustdesk 简介

RustDesk是一款优秀的免费开源的远程控制软件,采用rust语言编写,无需任何配置开箱即用。服务端代码开源,可自建中继节点,采用TLS 1.3端到端加密协议保护用户的通信安全,用户可以完全掌控数据,不用担心安全问题。可作为向日葵与TeamViewer的开源替代品。

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

官方文档:https://rustdesk.com/docs/zh-cn/manual/

rustdesk

8.2.2 搭建 rustdesk-server

项目地址:https://github.com/rustdesk/rustdesk-server

拉取镜像并运行hbbs与hbbr。

1
2
3
$ docker image pull rustdesk/rustdesk-server
$ docker run --name hbbs -p 21115:21115 -p 21116:21116 -p 21116:21116/udp -p 21118:21118 -v `pwd`:/root -it --net=host --rm rustdesk/rustdesk-server hbbs -r 自己的服务器IP // 运行hbbs
$ docker run --name hbbr -p 21117:21117 -p 21119:21119 -v `pwd`:/root -it --net=host --rm rustdesk/rustdesk-server hbbr // 运行hbbr

8.2.3 客户端配置自建服务器

使用公共服务器:无需配置即可使用。

使用私有服务器:找到“ID/中继服务器”配置,把ID服务器的地址填写成自己的服务器IP即可。

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] scp带密码拷贝文件 from CSDN

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

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

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

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

[28] linux下查看最消耗CPU、内存的进程 from CSDN

[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] docker安装RabbitMq from 稀土掘金

[42] docker简易搭建kafka from 知乎

[43] 中间件docker compose,包含redis、elasticsearch、mongo、mysql、rocketmq、kafka,一键启动 from github

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

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

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

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

[48] Docker容器及其内应用自启动解决方案 from CSDN

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

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

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

[52] ubuntu 中安装jdk脚本 from CSDN

[53] Ubuntu20中安装MySQL5.7 from Sail

[54] 访问后台出现重定向次数过多该怎么办 from CSDN

[55] Centos7.5安装java8 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] Cloudflare 5XX 错误故障排除 from Cloudflare官方文档

[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] linux下安装ffmpeg的详细教程 from 腾讯云

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

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

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

[98] 与 OneinStack 配合使用部署Halo from Halo官方文档

[99] rustdesk中继服务器的docker镜像使用 from CSDN

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

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

[102] umount.nfs: XXX: device is busy from CSDN

[103] 如何利用mount命令挂载另一台服务器上的目录 from CSDN

[104] Debian9.5 系统配置NFS配置说明 from 博客园

[105] Docker容器使用NFS from cloud-atlas

[106] 解决远程kafka本地无法连接问题 from IT Blog

[107] Shell中实现进度条的小脚本 from CSDN

[108] 解决Docker容器时区不正确的问题 form 简书