debian 安装 IntelliJ Idea ,并增加应用图标

对于桌面系统,没有图标是挺不方便的。我是用的是Debian 9,安装的桌面环境为 Gnome 3。

在下载 IntelliJ Idea 官方的Linux ide后,发现没有桌面图标,dock 上也不显示!

对于这种交互其实很早也有心理准备了,linux用户都是自己动手丰衣足食的。下载 idea 和制作idea图标快捷键步骤如下:

  1. 下载tgz包:https://www.jetbrains.com/idea/download/other.html

    选择一个合适的版本下载。

  2. 解压,我一般将软件放到 /var/local 目录下,给文件夹命名为idea:

    cd /var/local
    tar zxvf xxx.tar.gz
    mv xxx idea
    
  3. 做个命令行软链接,命令行方式启动也习惯性弄好。

    ln -s /var/local/idea/bin/idea.sh /usr/local/bin/idea
    
  4. 在桌面创建 idea.desktop文件

    [Desktop Entry]
    Name=IntelliJ IDEA
    Comment=IntelliJ IDEA
    Exec=/var/local/idea/bin/idea.sh
    Icon=/var/local/idea/bin/idea.png
    Terminal=false
    Type=Application
    Categories=Developer;
    

    image-20201130122330383

  5. 赋予权限

    chmod +r idea.desktop
    
  6. 可以复制一份到常用的图标归档的文件夹里

    cp idea.desktop /usr/share/applications
    

    这个文件夹里也有很多图标文件,可以都看看。gnome的图标路径一般存放在以下三个地方:

    • /usr/share/applications
    • /usr/local/share/applications
    • ~/.local/share/applications
  7. 下载常用的插件。

    列一些我常用的插件:

  8. 修改编辑器的字体大小

    在Linux下,idea的字体默认大小太小了,这样修改: File->Settings->Editor->Font

    image-20210303142348057

参考资料


gnome 3 中设置快捷键,快速启动终端

  1. 搜索setting,打开系统设置

    image-20201130115811716

    image-20201130115848336

  2. 搜索键盘配置 “shortcut”

    image-20201130115910613

  3. 增加自定义快捷键

    在键盘中拉到最下边,增加快捷键

    image-20201130115945986

  4. 增加终端的命令和快捷键

    /usr/bin/gnome-terminal
    

    image-20201130120034017

  5. 也可以修改一些常用的快捷键,比如我常用的截图快捷键,笔记本上 print screen其实比较麻烦的。

    image-20201130120201318

    另外记录一个无用的小知识,截图选区的命令为:

    gnome-screenshot -a -c
    

​ 笔记本上按 Alt + F4 也是比较麻烦的,参考mac的关闭窗口快捷键,我也设置了 Alt + Q 用来快捷关闭窗口。

参考资料


linux shell 命令备忘

不是专门的运维,时不时写shell脚本还要翻谷歌的感觉实在不太好。这篇文章记录几个常用的 shell 脚本命令,免得每次都从0开始查起。 这篇文章长期更新。

操作符

int型对比

if [ "$a" -eq "$b" ]
if [ "$a" -ne "$b" ]
if [ "$a" -gt "$b" ]
if [ "$a" -ge "$b" ]
if [ "$a" -lt "$b" ]
if [ "$a" -le "$b" ]
(("$a" < "$b"))
(("$a" <= "$b"))
(("$a" > "$b"))
(("$a" >= "$b"))

字符串对比


if [ "$a" = "$b" ]
if [ "$a" == "$b" ]
	[[ $a == z* ]]   # True if $a starts with an "z" (pattern matching).
	[[ $a == "z*" ]] # True if $a is equal to z* (literal matching).
	[ $a == z* ]     # File globbing and word splitting take place.
	[ "$a" == "z*" ] # True if $a is equal to z* (literal matching).
if [ "$a" != "$b" ]
if [[ "$a" < "$b" ]] 
if [[ "$a" > "$b" ]] 
if [ "$a" \< "$b" ] # 比较的是ASCII码
if [ "$a" \> "$b" ] # 比较的是ASCII码

if [ -z "$String" ] # string is null, that is, has zero length
if [ -n "$String" ] # string is not null

数组

SVC_LIST='app1:svc1(1|esvc2(1|svc3(1,app2:svc1(1|esvc2(1|svc3(1'

IFS=","
for LocalIpInfo in ${SVC_LIST[@]}
do
  IFS=":"
  local LocalArrayIPInfo=($LocalIpInfo)
  local LocalIP=${LocalArrayIPInfo[0]}
  local LocalIPFromSsh=`cat .ssh/config | grep -A 1 $LocalIP | grep HostName | cut -d " " -f 6`
  local LocalAppList=${LocalArrayIPInfo[1]}

  IFS="|"
  for LocalAppInfo in ${LocalAppList[@]}
  do
    IFS="("
    local LocalArrayAppInfo=($LocalAppInfo)
    local LocalApp=${LocalArrayAppInfo[0]}
    local LocalAppDesire=${LocalArrayAppInfo[1]}
    local LocalGrepInfo=($LocalApp)
  done
done

IFS=" "

for循环

nsArray2=(
abc
def
)

for ns in ${nsArray2[@]}
do
  cat <<EOF | kubectl apply -n $ns -f -
apiVersion: v1
kind: ResourceQuota
metadata:
  name: default-resourcequota
spec:
  hard:
    limits.cpu: "10m"
    requests.cpu: "10m"
    limits.memory: 10Mi
    requests.memory: 10Mi
    persistentvolumeclaims: "20"
    pods: "100"
    requests.storage: 1Mi
    services: "100"
EOF
done
kubectl get deployment -A|awk '{print $1,$2}'|grep -v NAMESPACE|while read vns vpod; 
do    
   vres=`kubectl get deployment -n $vns $vpod -oyaml|grep hostPath|wc -l`;    
    if [ $vres -gt 0 ];then       
     echo "hostpath,www,deployment,$vns,$vpod">>/tmp/www.csv
    fi; 
done
docker inspect $(docker ps -q)  --format '{{ .Name }} -> {{ .GraphDriver.Data.MergedDir}} ' |sed 's|/merged||g'

参考资料


docker,containerd,runc,docker-shim 之间的关系

在看系统进程的时候,发现了这样的进程关系:

systemd 里调用了 

- containerd -> containerd-shim
- dockerd -> docker-proxy

引起了我的兴趣。

ps: 另外上边只是在 docker 19.03 上发现了这样的调用关系,在 docker 17.06 上调用的关系实际上是这样:

-dockerd --registry-mirror=http:/xxx
  | -docker-containe -l unix:///xxx
      | -docker-containe   
  | -docker-proxy -proto xxx

在 19.03 版本中,docker相关的可执行文件如下:

image-20201011113355555

其中以docker开头的,docker, dockerd, docker-init, docker-proxy 是 docker 公司专属的,并非标准。

因为 docker 一直在开发中,网上很多资料都比较陈旧,不过八九不离十,无非是几个组件变了个名字:

  • docker,是一个客户端工具,用来把用户的请求发送给 docker daemon(dockerd)。
  • dockerd, docker daemon,一般也会被称为 docker engine。dockerd 启动时会启动 containerd 子进程。
  • Containerd 是一个工业级标准的容器运行时,它强调简单性、健壮性和可移植性,几乎囊括了单机运行一个容器运行时所需要的一切:执行,分发,监控,网络,构建,日志等。主要作用是:
    • 管理容器的生命周期(从创建容器到销毁容器)
    • 拉取/推送容器镜像
    • 存储管理(管理镜像及容器数据的存储)
    • 调用 runC 运行容器(与 runC 等容器运行时交互)
    • 管理容器网络接口及网络
  • ctr 是 containerd 的 cli。
  • 为了能够支持多种 OCI Runtime,containerd 内部使用 containerd-shim,每启动一个容器都会创建一个新的 containerd-shim 进程,指定容器 ID,Bundle 目录,运行时的二进制(比如 runc)。
  • RunC 是一个轻量级的工具,用来运行容器的,我们可以不用通过 docker 引擎,直接运行容器。事实上,runC 是标准化的产物,它根据 OCI 标准来创建和运行容器。

调用链主要就是下面这张图:

img

docker历史

至于容器架构为什么做的这么复杂,个人认为是技术、政治和历史等因素共同的结果。这里简单记录一下docker的历史:

  1. 自从 2013 年 docker 发布。
  2. 为了能够降低项目维护的成本,内部代码能够回馈社区,docker 公司提出了 “基础设施管道宣言” (Infrastructure Plumbing Manifesto),自行拆分自己项目中的管道代码并形成一个个新的开源项目:libcontainer, libnetwork, notary, hyperkit。
  3. 2015年 OCI 项目启动(开放容器标准),OCI 的技术委员会成员包括 Red Hat,Microsoft,Docker,Cruise,IBM,Google,Red Hat 和 SUSE,其中 Docker 公司有两名成员,且其中的一位是现任主席,具体的细节可以查看 OCI Technical Oversight Board
  4. docker 公司将 libcontainer 的实现移动到 runC 并捐赠给了 OCI。runC 包括了所有之前 docker 所使用的容器相关的与系统特性的代码。
  5. 2016 年,docker 开源并将 containerd 捐赠给了 CNCF。

与k8s相关

在容器标准的大战中,docker公司围绕docker swarm推出了CNM,Google等以屠龙者的姿态围绕 k8s 推出了CNI,目前来看,k8s已经奠定了在 PaaS 事实的地位。

CRI 是一套通过 protocol buffers 定义的 API,如下图:

img

kubelet 实现了 client 端,CRI shim 实现 server 端。只要实现CRI对应的接口,就能接入 k8s 作为 Container Runtime。

  1. k8s 1.5 中自己实现了 docker CRI shim,此时启动容器的流程如下:

    img

  2. 从 containerd 1.0 开始,为了能够减少一层调用的开销(废掉docker,也就是把上边的docker cri shim和docker踢掉),containerd 开发了一个新的 daemon,叫做 CRI-Containerd,直接与 containerd 通信,从而取代了 dockershim:

    img

  3. 但是这仍然多了一个独立的 daemon,从 containerd 1.1 开始,社区选择在 containerd 中直接内建 CRI plugin,通过方法调用来进行交互,从而减少一层 gRPC 的开销,最终的容器启动流程如下:

    img

    最终的结果是 k8s 的 Pod 启动延迟得到了降低,CPU 和内存占用率都有不同程度的降低。

  4. 但是这还不是终点,为了能够直接对接 OCI 的 runtime 而不是 containerd,社区孵化了 CRI-O 并加入了 CNCF。CRI-O 的目标是让 kubelet 与运行时直接对接,减少任何不必要的中间层开销。CRI-O 运行时可以替换为任意 OCI 兼容的 Runtime,镜像管理,存储管理和网络均使用标准化的实现。

@xuxinkun 的文章中有个图将他们之间的关系描绘的很清楚:

img

以下更新于2021年4月9日

关于Mesos

mesos于前天发起了关闭

参考资料


善用 nsenter 命令,更好地 debug 容器网络

https://staight.github.io/2019/09/23/nsenter%E5%91%BD%E4%BB%A4%E7%AE%80%E4%BB%8B/

在做容器 debug 的时候,经常出现容器里没有某个命令的尴尬局面。比如ping,telnet等常用命令。如何才能快速debug网络问题,又不需要安装软件呢?

那必须是nsenter命令了。 nsenter是一个可以在指定进程的命令空间下运行指定程序的命令,它最典型的用途就是进入容器的网络命令空间。具体可以参考官方文档:https://github.com/jpetazzo/nsenter.

nsenter 和 docker exec 之间的区别在于,nsenter不进入cgroup,因此规避了资源限制。

此外,nsenter也可以进入mnt, uts, ipc, pid, user命令空间,以及指定根目录和工作目录。

一、安装

我所在的系统默认装有 nsenter 命令。如果没有,按照官方文档如下安装:

$ wget https://www.kernel.org/pub/linux/utils/util-linux/v2.24/util-linux-2.24.tar.gz
$ tar -xzvf util-linux-2.24.tar.gz
$ cd util-linux-2.24/
$ ./configure --without-ncurses
$ make nsenter
$ sudo cp nsenter /usr/local/bin

然后可以查看nsenter自带的帮助查看命令使用方式:

nsenter -h

Usage:
nsenter [options] [<program> [<argument>...]]
 
Run a program with namespaces of other processes.
 
Options:
-a, --all enter all namespaces
-t, --target <pid> target process to get namespaces from
-m, --mount[=<file>] enter mount namespace
-u, --uts[=<file>] enter UTS namespace (hostname etc)
-i, --ipc[=<file>] enter System V IPC namespace
-n, --net[=<file>] enter network namespace
-p, --pid[=<file>] enter pid namespace
-C, --cgroup[=<file>] enter cgroup namespace
-U, --user[=<file>] enter user namespace
-S, --setuid <uid> set uid in entered namespace
-G, --setgid <gid> set gid in entered namespace
--preserve-credentials do not touch uids or gids
-r, --root[=<dir>] set the root directory
-w, --wd[=<dir>] set the working directory
-F, --no-fork do not fork before exec'ing <program>
-Z, --follow-context set SELinux context according to --target PID

二、 用法

首先,找出容器的PID:

PID=$(docker inspect --format {{.State.Pid} <容器名或id>)

然后:

nsenter --target $PID --mount --uts --ipc --net --pid -n /bin/sh

即可进入容器中,这个命令和 docker exec 命令效果几乎等同。当然也可以合并成一个命令。

比如进入 nginx 容器内,因为原本是没有telnet命令的,为了使用telnet命令,上面命令中的 –mount 参数不能带上,否则进去之后就找不到这个命令啦。最终使用的命令如下:

nsenter -t $(docker inspect --format '{{.State.Pid}}' nginx) -n /bin/bash

实际在这里我运行了宿主机的 bash 程序,获得了nginx容器的pid,然后进入该pid进程的network namespace,此时可以统计一下容器内有哪些网络端口:

image-20201010232030433

三、原理说明

以下参考:https://staight.github.io/2019/09/23/nsenter命令简介/

namespace

namespace是Linux中一些进程的属性的作用域,使用命名空间,可以隔离不同的进程。

Linux在不断的添加命名空间,目前有:

  • mount:挂载命名空间,使进程有一个独立的挂载文件系统,始于Linux 2.4.19
  • ipc:ipc命名空间,使进程有一个独立的ipc,包括消息队列,共享内存和信号量,始于Linux 2.6.19
  • uts:uts命名空间,使进程有一个独立的hostname和domainname,始于Linux 2.6.19
  • net:network命令空间,使进程有一个独立的网络栈,始于Linux 2.6.24
  • pid:pid命名空间,使进程有一个独立的pid空间,始于Linux 2.6.24
  • user:user命名空间,是进程有一个独立的user空间,始于Linux 2.6.23,结束于Linux 3.8
  • cgroup:cgroup命名空间,使进程有一个独立的cgroup控制组,始于Linux 4.6

Linux的每个进程都具有命名空间,可以在/proc/PID/ns目录中看到命名空间的文件描述符。

[root@staight ns]# pwd
/proc/1/ns
[root@staight ns]# ll
total 0
lrwxrwxrwx 1 root root 0 Sep 23 19:53 ipc -> ipc:[4026531839]
lrwxrwxrwx 1 root root 0 Sep 23 19:53 mnt -> mnt:[4026531840]
lrwxrwxrwx 1 root root 0 Sep 23 19:53 net -> net:[4026531956]
lrwxrwxrwx 1 root root 0 Sep 23 19:53 pid -> pid:[4026531836]
lrwxrwxrwx 1 root root 0 Sep 23 19:53 user -> user:[4026531837]
lrwxrwxrwx 1 root root 0 Sep 23 19:53 uts -> uts:[4026531838]

clone

clone是Linux的系统调用函数,用于创建一个新的进程。

clone和fork比较类似,但更为精细化,比如说使用clone创建出的子进程可以共享父进程的虚拟地址空间,文件描述符表,信号处理表等等。不过这里要强调的是,clone函数还能为新进程指定命名空间。

clone的语法:

 #define _GNU_SOURCE
#include <sched.h>

int clone(int (*fn)(void *), void *child_stack,
        int flags, void *arg, ...
        /* pid_t *ptid, void *newtls, pid_t *ctid */ );

其中flags即可指定命名空间,包括:

  • CLONE_NEWCGROUP:cgroup
  • CLONE_NEWIPC:ipc
  • CLONE_NEWNET:net
  • CLONE_NEWNS:mount
  • CLONE_NEWPID:pid
  • CLONE_NEWUSER:user
  • CLONE_NEWUTS:uts

使用示例:

pid = clone(childFunc, stackTop, CLONE_NEWUTS | SIGCHLD, argv[1]);

setns

clone用于创建新的命令空间,而setns则用来让当前线程(单线程即进程)加入一个命名空间。

语法:

#define _GNU_SOURCE             /* See feature_test_macros(7) */
#include <sched.h>

int setns(int fd, int nstype);

fd参数是一个指向一个命名空间的文件描述符,位于/proc/PID/ns/目录。

nstype指定了允许进入的命名空间,一般可设置为0,表示允许进入所有命名空间。

因此,往往该函数的用法为:

  1. 调用setns函数:指定该线程的命名空间。
  2. 调用execvp函数:执行指定路径的程序,创建子进程并替换父进程。

这样,就可以指定命名空间运行新的程序了。

代码示例:

#define _GNU_SOURCE
#include <fcntl.h>
#include <sched.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>

#define errExit(msg)    do { perror(msg); exit(EXIT_FAILURE); \
                        } while (0)

int
main(int argc, char *argv[])
{
    int fd;

    if (argc < 3) {
        fprintf(stderr, "%s /proc/PID/ns/FILE cmd args...\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    fd = open(argv[1], O_RDONLY); /* Get file descriptor for namespace */
    if (fd == -1)
        errExit("open");

    if (setns(fd, 0) == -1)       /* Join that namespace */
        errExit("setns");

    execvp(argv[2], &argv[2]);    /* Execute a command in namespace */
    errExit("execvp");
}

使用示例:

./ns_exec /proc/3550/ns/uts /bin/bash

nsenter

那么,最后就是nsenter了,nsenter相当于在setns的示例程序之上做了一层封装,使我们无需指定命名空间的文件描述符,而是指定进程号即可。

指定进程号 PID 以及需要进入的命名空间后,nsenter会帮我们找到对应的命名空间文件描述符/proc/PID/ns/FD,然后使用该命名空间运行新的程序。

参考资料


创建自定义 iptables 链

来自:How to create iptables firewall using custom chains

使用自定义链创建iptables防火墙,该自定义链将用于控制传入和传出流量。

创建iptables防火墙,该防火墙将允许已建立的连接,给定源地址的传入ssh,传出icmpntpdnssshhttphttps

# Flush rules and delete custom chains
iptables -F
iptables -X

# Define chain to allow particular source addresses
iptables -N chain-incoming-ssh
iptables -A chain-incoming-ssh -s 192.168.1.148 -j ACCEPT
iptables -A chain-incoming-ssh -s 192.168.1.149 -j ACCEPT
iptables -A chain-incoming-ssh -j DROP

# Define chain to allow particular services
iptables -N chain-outgoing-services
iptables -A chain-outgoing-services -p tcp --dport 53  -j ACCEPT
iptables -A chain-outgoing-services -p udp --dport 53  -j ACCEPT
iptables -A chain-outgoing-services -p tcp --dport 123 -j ACCEPT
iptables -A chain-outgoing-services -p udp --dport 123 -j ACCEPT
iptables -A chain-outgoing-services -p tcp --dport 80  -j ACCEPT
iptables -A chain-outgoing-services -p tcp --dport 443 -j ACCEPT
iptables -A chain-outgoing-services -p tcp --dport 22  -j ACCEPT
iptables -A chain-outgoing-services -p icmp            -j ACCEPT
iptables -A chain-outgoing-services -j DROP

# Define chain to allow established connections
iptables -N chain-states
iptables -A chain-states -p tcp  -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A chain-states -p udp  -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A chain-states -p icmp -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A chain-states -j RETURN

# Drop invalid packets
iptables -A INPUT -m conntrack --ctstate INVALID -j DROP

# Accept everything on loopback
iptables -A INPUT  -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT

# Accept incoming/outgoing packets for established connections
iptables -A INPUT  -j chain-states
iptables -A OUTPUT -j chain-states

# Accept incoming ICMP
iptables -A INPUT -p icmp -j ACCEPT

# Accept incoming SSH
iptables -A INPUT -p tcp --dport 22 -j chain-incoming-ssh

# Accept outgoing 
iptables -A OUTPUT -j chain-outgoing-services

## Drop everything else
iptables -P INPUT   DROP
iptables -P FORWARD DROP
iptables -P OUTPUT  DROP

列出所有防火墙规则,以验证是否按需应用了执行的命令。

$ sudo iptables -L -v -n

Chain INPUT (policy DROP 2 packets, 92 bytes)
 pkts bytes target              prot opt in     out     source               destination         
    0     0 DROP                all  --  *      *       0.0.0.0/0            0.0.0.0/0            ctstate INVALID
    1    29 ACCEPT              all  --  lo     *       0.0.0.0/0            0.0.0.0/0           
  190 15639 chain-states        all  --  *      *       0.0.0.0/0            0.0.0.0/0           
    0     0 ACCEPT              icmp --  *      *       0.0.0.0/0            0.0.0.0/0           
    1    60 chain-incoming-ssh  tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:22

Chain FORWARD (policy DROP 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         

Chain OUTPUT (policy DROP 0 packets, 0 bytes)
 pkts bytes target        prot opt in     out     source               destination         
    1    29 ACCEPT        all  --  *      lo      0.0.0.0/0            0.0.0.0/0           
  150 39893 chain-states  all  --  *      *       0.0.0.0/0            0.0.0.0/0           
    1    62 chain-outgoing-services  all  --  *      *       0.0.0.0/0            0.0.0.0/0           

Chain chain-incoming-ssh (1 references)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 ACCEPT     all  --  *      *       192.168.1.148        0.0.0.0/0           
    1    60 ACCEPT     all  --  *      *       192.168.1.149        0.0.0.0/0           
    0     0 DROP       all  --  *      *       0.0.0.0/0            0.0.0.0/0           

Chain chain-outgoing-services (1 references)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:53
    1    62 ACCEPT     udp  --  *      *       0.0.0.0/0            0.0.0.0/0            udp dpt:53
    0     0 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:123
    0     0 ACCEPT     udp  --  *      *       0.0.0.0/0            0.0.0.0/0            udp dpt:123
    0     0 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:80
    0     0 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:443
    0     0 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:22
    0     0 ACCEPT     icmp --  *      *       0.0.0.0/0            0.0.0.0/0           
    0     0 DROP       all  --  *      *       0.0.0.0/0            0.0.0.0/0           

Chain chain-states (2 references)
 pkts bytes target     prot opt in     out     source               destination         
  335 55240 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            ctstate RELATED,ESTABLISHED
    1    78 ACCEPT     udp  --  *      *       0.0.0.0/0            0.0.0.0/0            ctstate RELATED,ESTABLISHED
    0     0 ACCEPT     icmp --  *      *       0.0.0.0/0            0.0.0.0/0            ctstate RELATED,ESTABLISHED
    4   214 RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/0           

我已经使用了RETURNtarget,chain-states因此数据包将继续通过防火墙。

编辑地址清单

在源地址列表中列出防火墙规则。

$ sudo iptables -n --list chain-incoming-ssh --line-numbers

Chain chain-incoming-ssh (1 references)
num  target     prot opt source               destination         
1    ACCEPT     all  --  192.168.1.148        0.0.0.0/0           
2    ACCEPT     all  --  192.168.1.149        0.0.0.0/0           
3    DROP       all  --  0.0.0.0/0            0.0.0.0/0           

删除第一个条目。

$ sudo iptables -D chain-incoming-ssh  1

在链的开头添加新规则。

$ sudo iptables -I chain-incoming-ssh 1 -s 192.168.1.140 -j ACCEPT 

在上一个条目之前添加一个新规则。

$ sudo iptables -I chain-incoming-ssh 3 -s 192.168.1.150 -j ACCEPT 

在源地址列表中列出防火墙规则。

$ sudo iptables -n --list chain-incoming-ssh --line-numbers
Chain chain-incoming-ssh (1 references)
num  target     prot opt source               destination         
1    ACCEPT     all  --  192.168.1.140        0.0.0.0/0           
2    ACCEPT     all  --  192.168.1.149        0.0.0.0/0           
3    ACCEPT     all  --  192.168.1.150        0.0.0.0/0           
4    DROP       all  --  0.0.0.0/0            0.0.0.0/0           

补充说明

您可以使用以下命令检查特定的链条。

$ sudo iptables -n --list chain-outgoing-services

Chain chain-outgoing-services (1 references)
target     prot opt source               destination         
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:53
ACCEPT     udp  --  0.0.0.0/0            0.0.0.0/0            udp dpt:53
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:123
ACCEPT     udp  --  0.0.0.0/0            0.0.0.0/0            udp dpt:123
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:80
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:443
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:22
ACCEPT     icmp --  0.0.0.0/0            0.0.0.0/0           
DROP       all  --  0.0.0.0/0            0.0.0.0/0  

您还可以在shell脚本中使用它根据其存在来执行不同的操作。

iptables --list chain-outgoing-services &>/dev/null
if [ "$?" -eq "0" ]; then
  iptables -F chain-outgoing-services
else
  iptables -N chain-outgoing-services
fi