L B T

记 录 过 去 的 经 验

环境信息

  • Centos7 3.10.0-1160.45.1.el7
  • RabbitMQ 3.9.10

常见错误

RabbitMQ 启动失败

使用命令启动,报错

$ /sbin/rabbitmq-server -v
2023-04-26 10:02:47.621248+08:00 [noti] <0.146.0> Protocol 'inet_tcp': register/listen error: ehostunreach
2023-04-26 10:02:47.621248+08:00 [noti] <0.146.0>
2023-04-26 10:02:47.626643+08:00 [erro] <0.143.0> supervisor: {local,net_sup}
2023-04-26 10:02:47.626643+08:00 [erro] <0.143.0> errorContext: start_error
2023-04-26 10:02:47.626643+08:00 [erro] <0.143.0> reason: {'EXIT',nodistribution}
2023-04-26 10:02:47.626643+08:00 [erro] <0.143.0> offender: [{pid,undefined},
2023-04-26 10:02:47.626643+08:00 [erro] <0.143.0> {id,net_kernel},
2023-04-26 10:02:47.626643+08:00 [erro] <0.143.0> {mfargs,{net_kernel,start_link,
2023-04-26 10:02:47.626643+08:00 [erro] <0.143.0> [[rabbit_prelaunch_21812@localhost,
2023-04-26 10:02:47.626643+08:00 [erro] <0.143.0> shortnames],
2023-04-26 10:02:47.626643+08:00 [erro] <0.143.0> false,net_sup_dynamic]}},
2023-04-26 10:02:47.626643+08:00 [erro] <0.143.0> {restart_type,permanent},
2023-04-26 10:02:47.626643+08:00 [erro] <0.143.0> {shutdown,2000},
2023-04-26 10:02:47.626643+08:00 [erro] <0.143.0> {child_type,worker}]

关键错误信息 Protocol 'inet_tcp': register/listen error: ehostunreach,根据提示,可能是某个地址不可达,rabbitmq 启动时需要连接 epmd ,默认端口为 4369,在本地测试连接此端口,发现不通 [1]

$ curl -v 127.0.0.1:4369
* About to connect() to 127.0.0.1 port 4369 (#0)
* Trying 127.0.0.1...
* No route to host
* Failed connect to 127.0.0.1:4369; No route to host
* Closing connection 0
curl: (7) Failed connect to 127.0.0.1:4369; No route to host

根据输出的错误可知,是因为 127.0.0.1 无法连接,检查 iptables 防火墙策略,发现未允许回环网卡访问,在 iptables 中添加以下规则允许回环网卡访问

/etc/sysconfig/iptables
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [9020367577:7010759848370]
-A INPUT -i lo -j ACCEPT

允许回环网卡访问后,重新测试连接 epmd ,可以正常连接,重新启动 rabbitmq-server 正常。

$ curl -v 127.0.0.1:4369
* About to connect() to 127.0.0.1 port 4369 (#0)
* Trying 127.0.0.1...
* Connected to 127.0.0.1 (127.0.0.1) port 4369 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.29.0
> Host: 127.0.0.1:4369
> Accept: */*
>
* Empty reply from server
* Connection #0 to host 127.0.0.1 left intact
curl: (52) Empty reply from server

脚注

Macvlan

Macvlan 本身是 linxu kernel 模块

Macvlan 接口是物理以太网接口的虚拟子接口,Macvlan 允许用户在一个物理网络接口上面配置多个虚拟的网络接口,每个 Macvlan 接口都有自己的区别与父接口的 MAC 地址,并且可以像普通的物理网络接口一样分配 IP 地址。使用 Macvlan 技术实现的效果是一块物理网卡可以绑定多个 IP 地址,并且每个 IP 地址有自己独立的 MAC 地址。

Macvlan 虚拟出来的虚拟网卡,在逻辑上和物理网卡是对等的。使用 Macvlan 的虚拟网卡要和父接口在同一个网段。

Macvlan 的最大优点是性能极好,相比其他方式,macvlan 不需要创建 Linux bridge,而是直接通过interface 连接到物理网络。

为保证父接口能接收多个不同 MAC 地址的网络包,需要开启网卡的 混杂模式

docker 中使用 Macvlan 虚拟网卡

本示例演示 docker 环境中使用 macvlan。首先创建使用 macvlan 驱动的 network,Docker 中 macvlan 只支持 bridge 模式 [1]

$ docker network create -d macvlan --subnet=192.168.142.0/24 \
--gateway=192.168.142.2 \
-o parent=ens33 \
macvlan1

$ docker network ls
NETWORK ID NAME DRIVER SCOPE
69324d203c35 bridge bridge local
f8943f720d73 host host local
0aa95ac8c0f4 macvlan1 macvlan local
d400c40efdc5 none null local

在 docker 环境中,创建网络时,会自动将宿主机网卡设置为混杂模式,此时查看网卡信息,未显示混杂模式,但是查看 dmesg 日志,会看到网卡进入了混杂模式

$ dmesg
[93203.228311] device ens33 entered promiscuous mode

运行容器并连接到新建的 macvlan 网络 macvlan1

docker run -itd --name test01 \
--ip=192.168.142.12 \
--network macvlan1 centos:centos7.9.2009

使用命令 docker exec -it test01 bash 进入容器查看容器的 IP 地址信息,可以看到容器中的网卡类型为 macvlan,模式为 bridge,网关为 docker 网络 macvlan1 中配置的网关。

$ ip -d add
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 promiscuity 0 numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
4: eth0@if2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:c0:a8:8e:0c brd ff:ff:ff:ff:ff:ff link-netnsid 0 promiscuity 0
macvlan mode bridge numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535
inet 192.168.142.12/24 brd 192.168.142.255 scope global eth0
valid_lft forever preferred_lft forever

$ route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 192.168.142.2 0.0.0.0 UG 0 0 0 eth0
192.168.142.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0

测试容器可以和宿主机网络一样访问外网。

此时检查宿主机网卡信息,系统上只有 loens33docker0,未出现其他网卡。

$ ip -d link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 promiscuity 0 addrgenmode eui64 numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
link/ether 00:0c:29:90:51:eb brd ff:ff:ff:ff:ff:ff promiscuity 1 addrgenmode eui64 numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN mode DEFAULT group default
link/ether 02:42:e9:a6:76:56 brd ff:ff:ff:ff:ff:ff promiscuity 0
bridge forward_delay 1500 hello_time 200 max_age 2000 ageing_time 30000 stp_state 0 priority 32768 vlan_filtering 0 vlan_protocol 802.1Q bridge_id 8000.2:42:e9:a6:76:56 designated_root 8000.2:42:e9:a6:76:56 root_port 0 root_path_cost 0 topology_change 0 topology_change_detected 0 hello_timer 0.00 tcn_timer 0.00 topology_change_timer 0.00 gc_timer 265.03 vlan_default_pvid 1 vlan_stats_enabled 0 group_fwd_mask 0 group_address 01:80:c2:00:00:00 mcast_snooping 1 mcast_router 1 mcast_query_use_ifaddr 0 mcast_querier 0 mcast_hash_elasticity 16 mcast_hash_max 4096 mcast_last_member_count 2 mcast_startup_query_count 2 mcast_last_member_interval 100 mcast_membership_interval 26000 mcast_querier_interval 25500 mcast_query_interval 12500 mcast_query_response_interval 1000 mcast_startup_query_interval 3125 mcast_stats_enabled 0 mcast_igmp_version 2 mcast_mld_version 1 nf_call_iptables 0 nf_call_ip6tables 0 nf_call_arptables 0 addrgenmode eui64 numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535

在另一个 docker 节点上同样配置 docker 网络和容器

$ docker network create -d macvlan --subnet=192.168.142.0/24 \
--gateway=192.168.142.2 \
-o parent=ens33 \
macvlan1

$ docker run -itd --name test01 \
--ip=192.168.142.13 \
--network macvlan1 centos:centos7.9.2009

进入容器 test01 ,访问到另一个节点上的容器的连通性

$ ping 192.168.142.12
PING 192.168.142.12 (192.168.142.12) 56(84) bytes of data.
64 bytes from 192.168.142.12: icmp_seq=1 ttl=64 time=0.871 ms
64 bytes from 192.168.142.12: icmp_seq=2 ttl=64 time=0.403 ms
64 bytes from 192.168.142.12: icmp_seq=3 ttl=64 time=0.568 ms
^C
--- 192.168.142.12 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2047ms
rtt min/avg/max/mdev = 0.403/0.614/0.871/0.193 ms

进入容器 test01 ,测试和宿主机 ip 的连通性,结果发现不通,原因为:在 macvlan 虚拟网络中,父接口(物理网卡)相当于一个交换机,对于其子 macvlan 网卡的数据包,只进行转发而不处理,于是造成了使用本机 macvlan 网卡的虚拟 IP 无法和本机物理网卡的 IP 通信。

$ ping 192.168.142.10
PING 192.168.142.10 (192.168.142.10) 56(84) bytes of data.
From 192.168.142.13 icmp_seq=1 Destination Host Unreachable
From 192.168.142.13 icmp_seq=2 Destination Host Unreachable
From 192.168.142.13 icmp_seq=3 Destination Host Unreachable
^C
--- 192.168.142.10 ping statistics ---
5 packets transmitted, 0 received, +3 errors, 100% packet loss, time 4073ms
pipe 4
阅读全文 »

环境信息

  • Centos 7 5.4.239-1

Linux 的 namespace 的作用是 隔离内核资源,目前主要实现了以下 namespace

  • mount namespace - 文件系统挂载点
  • UTS namespace - 主机名
  • IPC namespace - POSIX 进程间通信消息队列
  • PID namespace - 进程 pid 数字空间
  • network namespace - network
  • user namespace - user ID 数字空间

其中,除了 network namespace,其他 namespace 的操作需要使用 C 语言调用系统 API 实现。network namespace 的增删改查功能已经集成到了 Linux 的 ip 工具集的 netns 子命令中

Linux 里面的 namespace 给处在其中的进程造成 2 个错觉:

  1. 它是系统里面唯一的进程
  2. 它独享系统的所有资源

默认情况下,Linux 里面的所有进程处在和宿主机相同的 namespace ,即初始 namespace 里,默认享有全局系统资源。

network namespace 常用操作

network namespace 的增删改查功能已经集成到了 Linux 的 ip 工具集的 netns 子命令中,因此在 Linux 系统中,对 network namespace 的操作主要使用 ip netns 命令

$ ip netns help
Usage: ip netns list
ip netns add NAME
ip netns set NAME NETNSID
ip [-all] netns delete [NAME]
ip netns identify [PID]
ip netns pids NAME
ip [-all] netns exec [NAME] cmd ...
ip netns monitor
ip netns list-id

创建并查看 network namespace

使用以下命令创建名为 netns1network namespace

ip netns add netns1

以下命令查看系统中的 network namespace

$ ip netns list
netns1

新的 network namespace 创建后,系统会在 /var/run/netns/ 下面生成一个同名的挂载点

$ ls -l /var/run/netns/
total 0
-r--r--r-- 1 root root 0 Apr 3 13:33 netns1

此挂载点的主要作用一方面是方便对 namespace 的管理,一方面是使 namespace 即使没有进程运行也能继续存在。

新的 network namespace 创建后,可以使用 ip netns exec 命令进入 namespace,做网络配置或者查询的工作。

ip netns exec 命令只能根据 network namespace 的名称进入 namespace

以下命令查询 netns1network namespace 的 IP 地址信息

$ ip netns exec netns1 ip add
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00

默认的 network namespace 除了附带一个 lo 网卡外,没有任何其他网络设备,并且此 lo 接口还处于 DOWN 的状态,因此此回环网卡也是不可访问的。

$ ip netns exec netns1 ping 127.0.0.1
connect: Network is unreachable

在此示例中,如果想启用本地回环地址,首先需要进入 namespace,将本地回环网卡的状态修改为 UP

$ ip netns exec netns1 ip link set dev lo up

$ ip netns exec netns1 ip add
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever

$ ip netns exec netns1 ping 127.0.0.1
PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.021 ms
^C
--- 127.0.0.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.021/0.021/0.021/0.000 ms

此时,namespace 中的 lo 网卡可以正常使用,但是因为 namespace 中没有其他网络设备,此 network namespace 无法和其他网络通信,要和其他网络通信,需要用到其他的网络技术,例如 veth pair

删除 network namespace

要删除 network namespace,可以使用以下命令

ip netns delete netns1

上面这条命令并没有实际删除 netns1 这个 network namespace,它只是移除了这个 namespace 对应的挂载点(/var/run/netns/netns1),只要里面的进程还运行着,network namespace 就会一直存在

veth pair

veth 是虚拟以太网(Virtual Ethernet)的缩写。veth 设备总是成对出现的,因此我们称之为 veth pairveth pair 的一端发送的数据会在另外一端接收。根据这一特性,veth pair 常被用于跨 network namespace 的通信,即分别将 veth pair 的 2 端放在不同的 network namespace

阅读全文 »

从 Linux 文件系统的角度看,tun/tap 设备是用户可以使用文件句柄操作的字符设备

从 Linux 网络虚拟化的角度看,tun/tap 设备是虚拟网卡,一端连接内核网络协议栈,一端连接用户态的程序。

tun/tap 设备主要的作用是可以将 TCP/IP 协议栈处理好的数据包发送给任何一个使用 tun/tap 设备驱动的程序,由用户态程序重新处理数据包后重新发送到 TCP/IP 协议栈。

tun/tap 设备的工作原理完全相同,主要区别在于:

  • tun 设备的 /dev/tunX 文件收发的是 IP 包,因此只能工作在网络层(L3),无法与物理网卡做桥接,可以通过三层交换(如 ip_forward) 与物理网卡交互
  • tap 设备的 /dev/tapX 文件收发的是数据链路层报文,可以与物理网卡做桥接。

tun/tap 设备的工作原理

上图展示了物理设备上的数据是如何通过 Linux 内核网络协议栈发送到用户态程序的。

物理网卡的数据送达网络协议栈,进程通过 Socket 创建特殊套接字,从网络协议栈接收数据。

从网络协议栈的角度看,tun/tap 设备这类虚拟网卡与物理网卡并无区别。对 tun/tap 设备而言,他与物理网卡的不同表现在它的数据源不是物理链路,而是来自用户态。

普通的物理网卡通过网线收发数据包,而 tun/tap 设备通过一个设备文件 (/dev/tunX/dev/tapX)收发数据包,所有对这个文件的写操作会通过 tun/tap 设备转换成一个网络数据包传送给内核的网络协议栈。当内核网络协议栈发送一个包给 tun/tap 设备时,用户态的进程通过读取设备文件,就可以拿到报的内容。用户态的程序也可以通过写入这个设备文件向 tun/tap 设备发送数据。

VPN 原理简述

如上图所示,整个数据包的流程包括

  1. App1 通过 Socket API 发送了一个数据包,假设这个数据包的目的 IP 地址是 192.168.1.3,和 tun0 位于同一个网段
  2. 数据包到达网络协议栈后,协议栈根据数据包的目的 IP 地址进行路由,匹配到数据包应该发送给 tun0 网卡,于是将数据包发送给 tun0 网卡
  3. tun0 网卡收到数据包,将数据包写入 /dev/tun0,/dev/tun0 由 App2 打开,于是 App2 获得了数据包
  4. App2 获得数据包后,通过报文封装,将原来的目的 IP 为 192.168.1.3 的报文封装在源 IP 为 eth0 的 IP,目的 IP 为 VPN 对端 IP 地址的报文中,构造出新的报文,并通过 Socket API 发送给内核网络协议栈
  5. 内核网络协议栈根据路由,发现数据包应该由 eth0 发送出去,于是将数据包发给 eth0,最终通过 eth0 将数据包发送到 VPN 的对端。

综上所述,发到 192.168.1.0/24 的数据包,首先通过监听在 tun0 设备上的 App2 (VPN 客户端)进行封包,再利用物理网卡 eth0 发送到远端网络的物理网卡上,从而实现 VPN。

VPN 网络报文真正从物理网卡出去需要经过 2 次内核网络协议栈,因此会有一定的性能损耗。

环境信息

  • Centos 7 5.4.239-1

Linux 的 namespace 的作用是 ”隔离内核资源“,目前主要实现了以下 namespace

  • mount namespace - 文件系统挂载点
  • UTS namespace - 主机名
  • IPC namespace - POSIX 进程间通信消息队列
  • PID namespace - 进程 pid 数字空间
  • network namespace - network
  • user namespace - user ID 数字空间
  • cgroup - 资源使用控制

其中,除了 network namespace,其他 namespace 的操作需要使用 C 语言调用系统 API 实现。network namespace 的增删改查功能已经集成到了 Linux 的 ip 工具集的 netns 子命令中

Linux 里面的 namespace 给处在其中的进程造成 2 个错觉:

  1. 它是系统里面唯一的进程
  2. 它独享系统的所有资源

默认情况下,Linux 里面的所有进程处在和宿主机相同的 namespace ,即初始 namespace 里,默认享有全局系统资源。

想要查看某个进程都在哪些 namespace 中,可以找到进程 ID (PID),通过查看以下内容或者 namespace 信息

$ ps -elf | grep nginx
4 S root 32679 32659 0 80 0 - 2248 sigsus Apr07 ? 00:00:00 nginx: master process nginx -g daemon off;

$ ll /proc/32679/ns/
total 0
lrwxrwxrwx 1 root root 0 Apr 19 13:51 cgroup -> cgroup:[4026531835]
lrwxrwxrwx 1 root root 0 Apr 19 13:51 ipc -> ipc:[4026534784]
lrwxrwxrwx 1 root root 0 Apr 19 13:51 mnt -> mnt:[4026534583]
lrwxrwxrwx 1 root root 0 Apr 19 13:51 net -> net:[4026534787]
lrwxrwxrwx 1 root root 0 Apr 19 13:51 pid -> pid:[4026534878]
lrwxrwxrwx 1 root root 0 Apr 19 13:51 pid_for_children -> pid:[4026534878]
lrwxrwxrwx 1 root root 0 Apr 19 13:51 user -> user:[4026531837]
lrwxrwxrwx 1 root root 0 Apr 19 13:51 uts -> uts:[4026534877]

通过以上命令,可以看到 nginx 进程所属的 namespace,要查看系统初始 namespace ,可以查看 PID 为 1 的进程的 namespace 信息

$ ll /proc/1/ns/
total 0
lrwxrwxrwx 1 root root 0 Apr 19 13:53 cgroup -> cgroup:[4026531835]
lrwxrwxrwx 1 root root 0 Apr 19 13:53 ipc -> ipc:[4026531839]
lrwxrwxrwx 1 root root 0 Apr 19 13:53 mnt -> mnt:[4026531840]
lrwxrwxrwx 1 root root 0 Apr 19 13:53 net -> net:[4026531992]
lrwxrwxrwx 1 root root 0 Apr 19 13:53 pid -> pid:[4026531836]
lrwxrwxrwx 1 root root 0 Apr 19 13:53 pid_for_children -> pid:[4026531836]
lrwxrwxrwx 1 root root 0 Apr 19 13:53 user -> user:[4026531837]
lrwxrwxrwx 1 root root 0 Apr 19 13:53 uts -> uts:[4026531838]

链接文件的内容的格式为 ns 类型: [inode number]。这里的 inode number 则用来标识一个 namespace,我们也可以把它理解为 namespace 的 ID。如果两个进程的某个 namespace 文件指向同一个链接文件,说明其相关资源在同一个 namespace 中。 [1]

脚注

sysctl 命令被用于在内核运行时动态地修改内核的运行参数,可用的内核参数在目录 /proc/sys 中。

sysctl 命令对内核参数的修改仅在当前生效,重启系统后参数丢失。如果希望参数永久生效可以修改配置文件 /etc/sysctl.conf

常用内核参数说明

内核参数 取值范围 含义 使用说明
kernel.hung_task_timeout_secs = 120 int 设置系统检测到进程阻塞(如 `D` 状态)后,等待进程结束的时常。
如果进程未在规定时间内结束,系统认为该进程无响应,则自动杀死以避免系统奔溃

mem

内核参数 取值范围 含义 使用说明
vm.min_free_kbytes = 2097152 单位 KB 设置系统最小剩余内存,以避免缓存不释放导致的死机
vm.oom-kill = 0 0,1
默认值为 1,开启
是否启用 OOM-killer。
特定情况下,可能不希望核心执行 OOM killer 的工作,关闭 OOM killer。 例如,排错时
echo 0 > /proc/sys/vm/oom-kill 临时关闭 [1]
vm.overcommit_memory = 0 0,1,2 内存分配策略
/proc/sys/vm/overcommit_memory
vm.overcommit_memory 详细说明
vm.overcommit_ratio = 50 int
default = 50
vm.overcommit_memory = 2 时才生效,配置允许 overcommit 的百分比 vm.overcommit_memory 详细说明
vm.panic_on_oom = 0 0,1
默认为 0 ,开启
表示当内存耗尽时,内核会触发 OOM killer 杀掉最耗内存的进程
vm.oom_kill_allocating_task = 0 0,1
默认为 0 ,不启用
OOM-Killer 时,是否选择当前正在申请内存的进程进行 kill
阅读全文 »

环境信息

  • Centos7 5.4.221-1.el7
  • Docker Engine - Community 20.10.9

本文档中的日志分析主要依赖于 journald 服务记录的日志,因此首先需要对 `journald` 服务记录的日志进行持久化配置

场景分析

k8s worker 节点经常死机(奔溃)

环境信息

  • Centos7 5.4.221-1.el7
  • Docker Engine - Community 20.10.9
  • Kubernetes v1.24.7

k8s 节点经常出现无响应(死机),重启才能恢复正常。重启恢复后,检查系统 messages 日志。

/var/log/messages
Feb 10 12:21:40 k8s-work1 kernel: INFO: task dockerd:1443 blocked for more than 368 seconds.
Feb 10 12:21:40 k8s-work1 kernel: Tainted: G E 5.4.221-1.el7.elrepo.x86_64 #1
Feb 10 12:21:40 k8s-work1 kernel: "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
Feb 10 12:21:40 k8s-work1 kernel: dockerd D 0 1443 1 0x00004080
Feb 10 12:21:40 k8s-work1 kernel: Call Trace:
Feb 10 12:21:40 k8s-work1 kernel: __schedule+0x2d2/0x730
Feb 10 12:21:40 k8s-work1 kernel: schedule+0x42/0xb0
Feb 10 12:21:40 k8s-work1 kernel: wb_wait_for_completion+0x56/0x90
Feb 10 12:21:40 k8s-work1 kernel: ? finish_wait+0x80/0x80
Feb 10 12:21:40 k8s-work1 kernel: sync_inodes_sb+0xd4/0x2c0
Feb 10 12:21:40 k8s-work1 kernel: ? __filemap_fdatawrite_range+0xf1/0x110
Feb 10 12:21:40 k8s-work1 kernel: sync_filesystem+0x5f/0xa0
Feb 10 12:21:40 k8s-work1 kernel: ovl_sync_fs+0x39/0x60 [overlay]
Feb 10 12:21:40 k8s-work1 kernel: sync_filesystem+0x79/0xa0
Feb 10 12:21:40 k8s-work1 kernel: generic_shutdown_super+0x27/0x110
Feb 10 12:21:40 k8s-work1 kernel: kill_anon_super+0x18/0x30
Feb 10 12:21:40 k8s-work1 kernel: deactivate_locked_super+0x3b/0x80
Feb 10 12:21:40 k8s-work1 kernel: deactivate_super+0x3e/0x50
Feb 10 12:21:40 k8s-work1 kernel: cleanup_mnt+0x109/0x160
Feb 10 12:21:40 k8s-work1 kernel: __cleanup_mnt+0x12/0x20
Feb 10 12:21:40 k8s-work1 kernel: task_work_run+0x8f/0xb0
Feb 10 12:21:40 k8s-work1 kernel: exit_to_usermode_loop+0x10c/0x130
Feb 10 12:21:40 k8s-work1 kernel: do_syscall_64+0x170/0x1b0
Feb 10 12:21:40 k8s-work1 kernel: entry_SYSCALL_64_after_hwframe+0x5c/0xc1
Feb 10 12:21:40 k8s-work1 kernel: RIP: 0033:0x55cf9a53e13b
Feb 10 12:21:40 k8s-work1 kernel: Code: Bad RIP value.
Feb 10 12:21:40 k8s-work1 kernel: RSP: 002b:000000c252fea778 EFLAGS: 00000212 ORIG_RAX: 00000000000000a6
Feb 10 12:21:40 k8s-work1 kernel: RAX: 0000000000000000 RBX: 000000c000070800 RCX: 000055cf9a53e13b
Feb 10 12:21:40 k8s-work1 kernel: RDX: 0000000000000000 RSI: 0000000000000002 RDI: 000000c2d000c3f0
Feb 10 12:21:40 k8s-work1 kernel: RBP: 000000c252fea7d0 R08: 0000000000000000 R09: 0000000000000000
Feb 10 12:21:40 k8s-work1 kernel: R10: 0000000000000000 R11: 0000000000000212 R12: 0000000000000000
Feb 10 12:21:40 k8s-work1 kernel: R13: 0000000000000001 R14: 000000000000000a R15: ffffffffffffffff

从日志中可看出,dockerd 进程处于 `D` 状态,说明 dockerd 在等待 IO 操作,根据进程调用的栈信息,显示存在对 overlay 文件系统的同步操作,初步猜测,可能是因为 overlay 文件系统中的某些操作未能及时完成,导致了 dockerd 进程的阻塞。

继续检查日志,看到系统连接 NFS 服务超时,怀疑可能是因为 NFS 异常导致。

/var/log/messages
Feb 10 12:21:40 k8s-work1 kernel: nfs: server 172.31.88.9 not responding, timed out
Feb 10 12:21:40 k8s-work1 kernel: nfs: server 172.31.88.9 not responding, still trying
Feb 10 12:21:40 k8s-work1 kernel: nfs: server 172.31.88.9 not responding, timed out
Feb 10 12:21:40 k8s-work1 kernel: nfs: server 172.31.88.9 not responding, still trying
Feb 10 12:21:40 k8s-work1 kernel: nfs: server 172.31.88.9 not responding, timed out

Linux 网卡的混杂模式(Promiscuous mode),简称 Promisc mode,俗称 监听模式。在非混杂模式下,网卡只会接受目的 MAC 地址是它自己的单播帧,以及多播帧;在混杂模式下,网卡会接受经过它的所有帧。

查看网卡是否处于 Promiscuous mode,可以使用 ifconfig 或者 netstat -i 命令

ifconfig ens33
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.142.10 netmask 255.255.255.0 broadcast 192.168.142.255
inet6 fe80::20c:29ff:fee7:c027 prefixlen 64 scopeid 0x20<link>
ether 00:0c:29:e7:c0:27 txqueuelen 1000 (Ethernet)
RX packets 194243 bytes 257521006 (245.5 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 92488 bytes 6051258 (5.7 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

当输出包含 PROMISC 时,表明该网络接口处于 Promiscuous mode,否则表明未处于 Promiscuous mode。要开启网卡的 Promiscuous mode ,可以使用以下命令

$ ifconfig ens33 promisc

$ ifconfig ens33
ens33: flags=4419<UP,BROADCAST,RUNNING,PROMISC,MULTICAST> mtu 1500
inet 192.168.142.10 netmask 255.255.255.0 broadcast 192.168.142.255
inet6 fe80::20c:29ff:fee7:c027 prefixlen 64 scopeid 0x20<link>
ether 00:0c:29:e7:c0:27 txqueuelen 1000 (Ethernet)
RX packets 194383 bytes 257531059 (245.6 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 92561 bytes 6058652 (5.7 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

以下命令使网卡退出 Promiscuous mode

ifconfig ens33 -promisc

将网络设备加入 Linux bridge 后,网络设备会自动进入混杂模式,此种情况使用 ifconfig 或者 netstat -i 命令查看网卡,未显示 PROMISC,但是查看内核日志,显示网卡已进入混杂模式,并且无法退出,直到将 veth 从Linux bridge 中移除。网络设备移除网桥后,会自动退出混杂模式。

$ ip link add veth0 type veth peer name veth1

$ brctl show
bridge name bridge id STP enabled interfaces
br0 8000.000000000000 no

$ brctl addif br0 veth0

$ ifconfig veth0
veth0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
inet 192.168.10.1 netmask 255.255.255.0 broadcast 192.168.10.255
ether b6:b3:aa:ae:61:05 txqueuelen 1000 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

$ netstat -i
Kernel Interface table
Iface MTU RX-OK RX-ERR RX-DRP RX-OVR TX-OK TX-ERR TX-DRP TX-OVR Flg
br0 1500 0 0 0 0 34 0 0 0 BMU
ens33 1500 195528 0 1 0 93168 0 0 0 BMPRU
veth0 1500 0 0 0 0 0 0 0 0 BMU

$ dmesg | grep promisc
[75099.376421] device veth2d80973 entered promiscuous mode
[77630.104784] device ens33 entered promiscuous mode
[77719.626596] device ens33 left promiscuous mode
[77877.905587] device ens33 entered promiscuous mode
[78153.928533] device veth0 entered promiscuous mode
阅读全文 »

Django 自带的 Admin Site 管理页面可以方便用户快速构建一个简单的后台管理系统,少量代码即可快速实现对数据库中的数据进行展示、修改、保存的可视化页面和功能。当需要对后台展示的数据进行配置时,只需要在 app 的代码文件 admin.py 中进行相应配置即可。

环境信息

  • centos 7
  • python 3.10
  • django 4.0

为 model 配置 admin 管理页面

要为 model 启用 admin 管理接口,参考配置

阅读全文 »

环境信息

  • Centos 7
  • mongodb 4.0.26

下载安装

官方社区版下载页面

wget https://repo.mongodb.org/yum/redhat/7/mongodb-org/4.0/x86_64/RPMS/mongodb-org-shell-4.0.28-1.el7.x86_64.rpm
wget https://repo.mongodb.org/yum/redhat/7/mongodb-org/4.0/x86_64/RPMS/mongodb-org-mongos-4.0.28-1.el7.x86_64.rpm
wget https://repo.mongodb.org/yum/redhat/7/mongodb-org/4.0/x86_64/RPMS/mongodb-org-server-4.0.28-1.el7.x86_64.rpm
wget https://repo.mongodb.org/yum/redhat/7/mongodb-org/4.0/x86_64/RPMS/mongodb-org-tools-4.0.28-1.el7.x86_64.rpm

yum localinstall mongodb-org-mongos-4.0.28-1.el7.x86_64.rpm mongodb-org-tools-4.0.28-1.el7.x86_64.rpm mongodb-org-server-4.0.28-1.el7.x86_64.rpm mongodb-org-shell-4.0.28-1.el7.x86_64.rpm

环境信息

  • Python 3.11
  • Django 4.1

admin 模板解析

Django 模板之间存在各种复杂的继承关系,最基础的模板为 base.html,文件位于 python3.11/site-packages/django/contrib/admin/templates/admin/base.html。下面以 Admin 页面中的各个模块来解析实现对应模块的模板及代码。

title

title 指网页标题,以 Admin 站点的首页为例,首页的模板文件 index.html 中未定义 title 信息,而是继承自 base_site.html

base_site.html
{% extends "admin/base.html" %}

{% block title %}{% if subtitle %}{{ subtitle }} | {% endif %}{{ title }} | {{ site_title|default:_('Django site admin') }}{% endblock
%}

base_site.html 模板继承了模板 base.html,并使用 {% block title %} 标签复写了继承自 base.html 模板的 title 信息。默认显示 Django site admin,如果应用的 admin.py 中定义了 admin.site.site_title,则显示其内容

base.html
{% load i18n static %}<!DOCTYPE html>
{% get_current_language as LANGUAGE_CODE %}{% get_current_language_bidi as LANGUAGE_BIDI %}
<html lang="{{ LANGUAGE_CODE|default:"en-us" }}" dir="{{ LANGUAGE_BIDI|yesno:'rtl,ltr,auto' }}">
<head>
<title>{% block title %}{% endblock %}</title>

基础模板 base.htmltitle 信息默认为空。

Django 管理或站点标题

Admin 管理页面最顶部左上角会展示默认的 Django 管理 或者站点标题,如果应用的 admin.py 中配置了 admin.site.site_header,则显示站点标题,这是一个链接,点击后会跳转首页。

这部分的实现是通过继承 base_site.html 实现,其中的 {% block branding %} 定义了这部分内容。

base_site.html
{% extends "admin/base.html" %}

{% block title %}{% if subtitle %}{{ subtitle }} | {% endif %}{{ title }} | {{ site_title|default:_('Django site admin') }}{% endblock %}

{% block branding %}
<h1 id="site-name"><a href="{% url 'admin:index' %}">{{ site_header|default:_('Django administration') }}</a></h1>
{% endblock %}

{% block nav-global %}{% endblock %}

用户欢迎信息

Django admin 站点默认会显示如下的欢饮信息及修改密码、注销等链接

此处的配置位于 base.html 中的 {% block usertools %} 块内,{% block usertools %} 块位于 {% block header %} 块内。

base.html
{% block header %}
<div id="header">
<div id="branding">
{% block branding %}{% endblock %}
</div>
{% block usertools %}
{% if has_permission %}
<div id="user-tools">
{% block welcome-msg %}
{% translate 'Welcome,' %}
<strong>{% firstof user.get_short_name user.get_username %}</strong>.
{% endblock %}
{% block userlinks %}
{% if site_url %}
<a href="{{ site_url }}">{% translate 'View site' %}</a> /
{% endif %}
{% if user.is_active and user.is_staff %}
{% url 'django-admindocs-docroot' as docsroot %}
{% if docsroot %}
<a href="{{ docsroot }}">{% translate 'Documentation' %}</a> /
{% endif %}
{% endif %}
{% if user.has_usable_password %}
<a href="{% url 'admin:password_change' %}">{% translate 'Change password' %}</a> /
{% endif %}
<a href="{% url 'admin:logout' %}">{% translate 'Log out' %}</a>
{% endblock %}
</div>
{% endif %}
{% endblock %}
{% block nav-global %}{% endblock %}
</div>
{% endblock %}

自定义页面

自定义和 Django admin 风格一样的页面

如果要自定义自己的页面,并实现和 Django admin 一致的风格,比如一样的 branding 和用户欢迎信息,可以使用如下代码实现

{% extends "admin/base_site.html" %}
{% load i18n static %}

{% block title %}
My Customize Site
{% endblock %}

{% block extrastyle %}

{% endblock %}

{% block branding %}
<h1 id="site-name"><a href="{% url 'admin:index' %}">My Customize Site</a></h1>
{% endblock %}

{% block usertools %}
<div id="user-tools">
{% block welcome-msg %}
{% translate 'Welcome,' %}
<strong>{% firstof user.get_short_name user.get_username %}</strong>.
{% endblock %}
{% block userlinks %}
{% if site_url %}
<a href="{{ site_url }}">{% translate 'View site' %}</a> /
{% endif %}
{% if user.is_active and user.is_staff %}
{% url 'django-admindocs-docroot' as docsroot %}
{% if docsroot %}
<a href="{{ docsroot }}">{% translate 'Documentation' %}</a> /
{% endif %}
{% endif %}
{% if user.has_usable_password %}
<a href="{% url 'admin:password_change' %}">{% translate 'Change password' %}</a> /
{% endif %}
<a href="{% url 'admin:logout' %}">{% translate 'Log out' %}</a>
{% endblock %}
</div>

{% endblock %}

{% block breadcrumbs %}{% endblock %}
{% block content %}
hello world
{% endblock %}



环境信息

  • Python3.11
  • Django4

django-bootstrap5 安装配置

pip install django-bootstrap5

在项目配置文件 settings.py 中添加应用名

settings.py

INSTALLED_APPS = [
...
'django_bootstrap5',
]

bootstrap5 使用

环境信息

  • Mysql 5.7

常用 sql

导出数据

导出到文件

SELECT * FROM [TABLE] 
INTO OUTFILE '[FILE]'
FIELDS TERMINATED BY ','
OPTIONALLY ENCLOSED BY '"'
LINES TERMINATED BY '\n'

参数说明:

  • into outfile ‘导出的目录和文件名’
  • fields terminated by ‘字段间分隔符’
  • optionally enclosed by ‘字段包围符’
  • optionally enclosed by 对数值型字段无效

  • lines terminated by ‘行间分隔符’

产生报错可参考 Mysql 常见错误

插入数据

批量插入

insert into tb(c1,c2) values(1,2),(3,4),(5,6);
阅读全文 »

环境信息

  • Centos 7
  • Mysql 5.7
  • Percona-XtraBackup-2.4.4

恢复方法1:mysqldump 主库锁表备份恢复

前提 : 接受主库锁表操作,备份恢复过程中主库无法写入数据

从库停止slave进程

登录 mysql 从库,执行以下命令,停止 slave 进程

stop slave;
阅读全文 »

常见错误

error: RPC failed; HTTP 403 curl 22 The requested URL returned error: 403

错误场景 : windows 系统中 git push 报错

错误原因 : 大概率为用户密码错误

排查步骤

  1. 清除 windows 凭据管理中的 git 密码,或更改为正确的密码
  2. 编辑 .git/config 文件,对 url 按照如下格式配置:
    .git/config
    url = http://[email protected]/test.git
    其中 USERNAME 为用户名,重新执行 git push,此时会要求输入用户密码,输入正确的用户密码后,可正常执行

There is no tracking information for the current branch

执行 git pull 命令时报错:

$ git pull
There is no tracking information for the current branch.
Please specify which branch you want to merge with.
See git-pull(1) for details

git pull <remote> <branch>

If you wish to set tracking information for this branch you can do so with:

git branch --set-upstream-to=origin/<branch> activity

此错误原因为本地的分支(activity)未和远程分支建立关联,根据提示,执行以下命令建立关联关系

$ git branch --set-upstream-to=origin/activity origin/xhy-activity
warning: refname 'origin/activity' is ambiguous.
fatal: Ambiguous object name: 'origin/activity'.

执行报错: fatal: Ambiguous object name: 'origin/activity'.,此报错原因为本地已存在分支 origin/activity,远程也存在此分支,导致 git 无法分辨。可以执行以下命令重命名本地分支

git branch -m origin/activity activity

重新建立关联关系

$ git branch --set-upstream-to=origin/activity activity
Branch activity set up to track remote branch activity from origin.

关联正常后,执行 git pull 正常。

internetbs 域名注册平台 API 接口稳定

调用 API 接口需要使用 API key 及账号密码。API 接口申请 key 时需要添加 IP 白名单,只允许从添加的白名单 IP 请求 API。

常见操作

获取域名数量

API 默认返回的数据格式为 TEXT,建议指定数据返回格式为 JSON,通过 eval(response.content) 将返回的字节类型数据转换为字典类型。

>>> params = {'ApiKey': 'key', 'Password': 'pswd', 'ResponseFormat': 'JSON'}

>>> response = requests.get('https://api.internet.bs/Domain/Count', params=params, )

>>> response.content
b'{"transactid":"3b3df8bfdfcc215ea7e6575a97adcea3","status":"SUCCESS","app":9,"com":6,"de":1,"in":1,"live":1,"tv":2,"vip":1,"world":1,"totaldomains":22}'

>>> eval(response.content)
{'transactid': '3b3df8bfdfcc215ea7e6575a97adcea3', 'status': 'SUCCESS', 'app': 9, 'com': 6, 'de': 1, 'in': 1, 'live': 1, 'tv': 2, 'vip': 1, 'world': 1, 'totaldomains': 22}

获取所有域名

>>> params = {'ApiKey': 'key', 'Password': 'pswd', 'ResponseFormat': 'JSON'}

>>> response = requests.get('https://api.internet.bs/Domain/List', params=params, )

Namesilo api 官方文档

Python SDK 为 python-namesilo,安装方法

pip install python-namesilo

环境信息

  • Python 3.11.2
  • python-namesilo==1.1.3

python-namesilo 常见用法示例

获取账号中的所有域名

使用 SDK 之前需要先登陆账号创建 API Token,详细使用方法可以查看帮助信息,获取所有域名使用方法 list_domains

>>> from namesilo.core import NameSilo
>>> key = 'KKKKKKKKKKKKKKKKKK'

>>> client = NameSilo(token=key, sandbox=False)

>>> help(client)

>>> client.list_domains()

获取指定域名的详细信息

获取指定域名的详细信息使用 get_domain_info,此方法返回一个 DomainInfo 对象,里面包括域名创建时间,过期时间,nameserver等信息

>>> client.get_domain_info('test.app')
<namesilo.common.models.DomainInfo object at 0x7f71a0530a50>

>>> dir(client.get_domain_info('test.app'))
['auto_renew', 'contacts', 'created', 'expires', 'locked', 'name_servers', 'private', 'status', 'traffic_type']

定时同步数据到 Linux rsync 服务器

脚本内容如下,本示例中 Windows 版 rsync 客户端安装位置: d:\cwrsync_6.2.4_x64_free\,密码文件路径:d:\cwrsync_6.2.4_x64_free\rsync.client.pswd


:start
cd d:\
cd cwrsync_6.2.4_x64_free

.\bin\rsync.exe --progress -a -c -r -u -t --timeout=300 -z --password-file rsync.client.pswd --exclude '.idea' --exclude 'rsync2Server.bat' /cygdrive/d/cwrsync_6.2.4_x64_free/data/ rsync@${RSYNC_SERVER}:backup

choice /t 5 /d y /n >nul

goto start

环境信息

  • Centos 7 3.10.0-1160
  • Docker 20.10.9
  • iptables

前提条件

宿主机操作系统内核配置允许数据转发,开启系统 IPv4 转发功能

Docker 部署 OpenVPN 服务端步骤

创建本地配置目录

用了在启动容器时挂载以持久化 OpenVPN 配置

mkdir /opt/openvpn1/

初始化配置文件

执行以下命令初始化 OpenVPN 服务端配置

docker run --rm \
-v /opt/openvpn1/:/etc/openvpn \
kylemanna/openvpn:2.4 ovpn_genconfig -u udp://${PUB_IP}:1194

参数说明:

  • udp://${PUB_IP}:1194 - 指定 VPN 服务器配置,使用 1194/udp 端口。${PUB_IP} 为服务器公网 IP。

生成密钥(证书)文件

docker run --rm -it \
-v /opt/openvpn1/:/etc/openvpn \
kylemanna/openvpn:2.4 ovpn_initpki

根据提示,输入 CA 根证书密码及名称

创建带有密码的客户端证书

执行以下命令,根据提示输入客户端证书密码及 CA 密码,生成客户端证书。如果客户端证书无需密码,最后加选项 nopass

docker run --rm -it \
-v /opt/openvpn1/:/etc/openvpn \
kylemanna/openvpn:2.4 easyrsa build-client-full vpn1

导出客户端证书

docker run --rm -it \
-v /opt/openvpn1/:/etc/openvpn \
kylemanna/openvpn:2.4 ovpn_getclient vpn1 > /opt/openvpn/client/vpn1.ovpn

启动 OpenVPN

docker run -it --name OpenVPN1 \
-v /opt/openvpn1/:/etc/openvpn \
-d -p 1194:1194/udp --cap-add=NET_ADMIN \
kylemanna/openvpn:2.4

防火墙放通 1194/udp 端口

/etc/sysconfig/iptables
-A INPUT -p udp --dport 1194 -j ACCEPT -m comment --comment "openvpn"

OpenVPN 启动后,docker 会在宿主机操作系统的 iptables 中添加对应的 MASQUERADE 规则,负责转发和 NAT 数据,具体规则可通过以下方法查看

查看 NAT 表添加的规则

$ iptables -t nat -L -v -n --line-numbers | more
Chain PREROUTING (policy ACCEPT 127 packets, 9255 bytes)
num pkts bytes target prot opt in out source destination
1 54 2490 DOCKER all -- * * 0.0.0.0/0 0.0.0.0/0 ADDRTYPE match dst-type LOCAL

Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
num pkts bytes target prot opt in out source destination

Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
num pkts bytes target prot opt in out source destination
1 0 0 DOCKER all -- * * 0.0.0.0/0 !127.0.0.0/8 ADDRTYPE match dst-type LOCAL

Chain POSTROUTING (policy ACCEPT 1 packets, 70 bytes)
num pkts bytes target prot opt in out source destination
1 75 6875 MASQUERADE all -- * !docker0 172.17.0.0/16 0.0.0.0/0
2 610 36387 MASQUERADE all -- * * 10.8.0.0/24 0.0.0.0/0
3 0 0 MASQUERADE udp -- * * 172.17.0.2 172.17.0.2 udp dpt:1194

Chain DOCKER (2 references)
num pkts bytes target prot opt in out source destination
1 0 0 RETURN all -- docker0 * 0.0.0.0/0 0.0.0.0/0
2 1 70 DNAT udp -- !docker0 * 0.0.0.0/0 0.0.0.0/0 udp dpt:1194 to:172.17.0.2:1194

查看 FILTER 表添加的规则

$ iptables -L -v -n --line-numbers | more
Chain INPUT (policy DROP 0 packets, 0 bytes)
num pkts bytes target prot opt in out source destination
1 641 51489 ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED
2 0 0 ACCEPT all -- lo * 0.0.0.0/0 0.0.0.0/0
3 0 0 ACCEPT udp -- * * 0.0.0.0/0 0.0.0.0/0 udp dpt:1194 /* openvpn */
...
13 0 0 ACCEPT icmp -- * * 0.0.0.0/0 0.0.0.0/0 icmptype 8
14 0 0 ACCEPT icmp -- * * 0.0.0.0/0 0.0.0.0/0 icmptype 0
15 230 14788 REJECT all -- * * 0.0.0.0/0 0.0.0.0/0 reject-with icmp-host-prohibited

Chain FORWARD (policy DROP 0 packets, 0 bytes)
num pkts bytes target prot opt in out source destination
1 16891 4860K DOCKER-USER all -- * * 0.0.0.0/0 0.0.0.0/0
2 16891 4860K DOCKER-ISOLATION-STAGE-1 all -- * * 0.0.0.0/0 0.0.0.0/0
3 8465 2439K ACCEPT all -- * docker0 0.0.0.0/0 0.0.0.0/0 ctstate RELATED,ESTABLISHED
4 1 70 DOCKER all -- * docker0 0.0.0.0/0 0.0.0.0/0
5 8425 2421K ACCEPT all -- docker0 !docker0 0.0.0.0/0 0.0.0.0/0
6 0 0 ACCEPT all -- docker0 docker0 0.0.0.0/0 0.0.0.0/0
7 4177 1774K ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED
8 202 13030 REJECT all -- * * 0.0.0.0/0 0.0.0.0/0 reject-with icmp-host-prohibited

Chain OUTPUT (policy ACCEPT 343 packets, 61383 bytes)
num pkts bytes target prot opt in out source destination

Chain DOCKER (1 references)
num pkts bytes target prot opt in out source destination
1 1 70 ACCEPT udp -- !docker0 docker0 0.0.0.0/0 172.17.0.2 udp dpt:1194

Chain DOCKER-ISOLATION-STAGE-1 (1 references)
num pkts bytes target prot opt in out source destination
1 8425 2421K DOCKER-ISOLATION-STAGE-2 all -- docker0 !docker0 0.0.0.0/0 0.0.0.0/0
2 16891 4860K RETURN all -- * * 0.0.0.0/0 0.0.0.0/0

Chain DOCKER-ISOLATION-STAGE-2 (1 references)
num pkts bytes target prot opt in out source destination
1 0 0 DROP all -- * docker0 0.0.0.0/0 0.0.0.0/0
2 8425 2421K RETURN all -- * * 0.0.0.0/0 0.0.0.0/0

Chain DOCKER-USER (1 references)
num pkts bytes target prot opt in out source destination
1 16891 4860K RETURN all -- * * 0.0.0.0/0 0.0.0.0/0

客户端连接

导出客户端证书 中生成的客户端证书发送到客户端,测试连接。

客户端连接失败,可以检查以下内容:

  • 客户端日志及服务端日志,服务端日志可以通过以下方法查看

    docker logs -f OpenVPN
  • 检查是否是因为 iptables 防火墙规则 问题导致无法连接,如果防火墙相关规则丢失,可以通过重启 docker 和 OpenVPN 容器的方式恢复。

  • 检查容器中启动的端口和 docker 映射的端口是否一致。

常用选项

选项 说明 示例
-c 打包文件
-x 解包
-t 检测打包文件中的内容 tar -tf test.tar
-f 目标文件名称,要打包或解包的文件名 tar -cf test.tar test
tar -xf test.tar
--exclude 打包时排除文件
打包的目录使用相对路径,排除的文件只能接相对路径
打包的目录使用绝对路径,排除的文件接相对路径或绝对路径
tar -cf test.tar test --exclude=runtime/*
阅读全文 »