gnome 3 命令行打开当前目录
2020-10-13 tech linux gnome 1 mins 124 字

gnome 3 的文件管理器为 nautillus。 在命令行中打开当前文件夹的命令为:
nautilus .
如果需要已特定用户的身份打开,先切换用户即可,例如:
su kelu
nautilus .
不加上路径则默认打开 home 目录:
nautilus

gnome 3 的文件管理器为 nautillus。 在命令行中打开当前文件夹的命令为:
nautilus .
如果需要已特定用户的身份打开,先切换用户即可,例如:
su kelu
nautilus .
不加上路径则默认打开 home 目录:
nautilus

对于桌面系统,没有图标是挺不方便的。我是用的是Debian 9,安装的桌面环境为 Gnome 3。
在下载 IntelliJ Idea 官方的Linux ide后,发现没有桌面图标,dock 上也不显示!
对于这种交互其实很早也有心理准备了,linux用户都是自己动手丰衣足食的。下载 idea 和制作idea图标快捷键步骤如下:
下载tgz包:https://www.jetbrains.com/idea/download/other.html
选择一个合适的版本下载。
解压,我一般将软件放到 /var/local 目录下,给文件夹命名为idea:
cd /var/local
tar zxvf xxx.tar.gz
mv xxx idea
做个命令行软链接,命令行方式启动也习惯性弄好。
ln -s /var/local/idea/bin/idea.sh /usr/local/bin/idea
在桌面创建 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;

赋予权限
chmod +r idea.desktop
可以复制一份到常用的图标归档的文件夹里
cp idea.desktop /usr/share/applications
这个文件夹里也有很多图标文件,可以都看看。gnome的图标路径一般存放在以下三个地方:
下载常用的插件。
列一些我常用的插件:
修改编辑器的字体大小
在Linux下,idea的字体默认大小太小了,这样修改: File->Settings->Editor->Font


搜索setting,打开系统设置


搜索键盘配置 “shortcut”

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

增加终端的命令和快捷键
/usr/bin/gnome-terminal

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

另外记录一个无用的小知识,截图选区的命令为:
gnome-screenshot -a -c
笔记本上按 Alt + F4 也是比较麻烦的,参考mac的关闭窗口快捷键,我也设置了 Alt + Q 用来快捷关闭窗口。

不是专门的运维,时不时写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=" "
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'

在看系统进程的时候,发现了这样的进程关系:
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相关的可执行文件如下:

其中以docker开头的,docker, dockerd, docker-init, docker-proxy 是 docker 公司专属的,并非标准。
因为 docker 一直在开发中,网上很多资料都比较陈旧,不过八九不离十,无非是几个组件变了个名字:
containerd-shim,每启动一个容器都会创建一个新的 containerd-shim 进程,指定容器 ID,Bundle 目录,运行时的二进制(比如 runc)。调用链主要就是下面这张图:

至于容器架构为什么做的这么复杂,个人认为是技术、政治和历史等因素共同的结果。这里简单记录一下docker的历史:
libcontainer 的实现移动到 runC 并捐赠给了 OCI。runC 包括了所有之前 docker 所使用的容器相关的与系统特性的代码。在容器标准的大战中,docker公司围绕docker swarm推出了CNM,Google等以屠龙者的姿态围绕 k8s 推出了CNI,目前来看,k8s已经奠定了在 PaaS 事实的地位。
CRI 是一套通过 protocol buffers 定义的 API,如下图:

kubelet 实现了 client 端,CRI shim 实现 server 端。只要实现CRI对应的接口,就能接入 k8s 作为 Container Runtime。
k8s 1.5 中自己实现了 docker CRI shim,此时启动容器的流程如下:

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

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

最终的结果是 k8s 的 Pod 启动延迟得到了降低,CPU 和内存占用率都有不同程度的降低。
但是这还不是终点,为了能够直接对接 OCI 的 runtime 而不是 containerd,社区孵化了 CRI-O 并加入了 CNCF。CRI-O 的目标是让 kubelet 与运行时直接对接,减少任何不必要的中间层开销。CRI-O 运行时可以替换为任意 OCI 兼容的 Runtime,镜像管理,存储管理和网络均使用标准化的实现。
@xuxinkun 的文章中有个图将他们之间的关系描绘的很清楚:

以下更新于2021年4月9日
mesos于前天发起了关闭

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,此时可以统计一下容器内有哪些网络端口:

namespace是Linux中一些进程的属性的作用域,使用命名空间,可以隔离不同的进程。
Linux在不断的添加命名空间,目前有:
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是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即可指定命名空间,包括:
使用示例:
pid = clone(childFunc, stackTop, CLONE_NEWUTS | SIGCHLD, argv[1]);
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,表示允许进入所有命名空间。
因此,往往该函数的用法为:
这样,就可以指定命名空间运行新的程序了。
代码示例:
#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相当于在setns的示例程序之上做了一层封装,使我们无需指定命名空间的文件描述符,而是指定进程号即可。
指定进程号 PID 以及需要进入的命名空间后,nsenter会帮我们找到对应的命名空间文件描述符/proc/PID/ns/FD,然后使用该命名空间运行新的程序。

使用自定义链创建iptables防火墙,该自定义链将用于控制传入和传出流量。
创建iptables防火墙,该防火墙将允许已建立的连接,给定源地址的传入ssh,传出icmp,ntp,dns,ssh,http和https。
# 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