L B T

记 录 过 去 的 经 验

Outline 官网

Outline 是由附属于 Google 的 Jigsaw 开发的开源的 VPN 软件。它的设计目标是为了实现 VPN 的简单部署和管理以及安全。Outline 提供了强加密、用户管理工具、并支持多平台,包括 Windows, macOS, Linux, iOS, 和 Android。

Outline 主要由 2 部分组成:

  • Outline Manager : 用来部署 VPN 服务器,以及管理用户、限速等
  • Outline Client : 连接 VPN 的客户端,支持多平台

本文示例基本环境信息

  • Ubuntu 22.04.4 LTS (Jammy Jellyfish)
  • Outline Manager Version 1.15.2

Outline 环境 部署

Outline Manager 部署

Outline Manager 部署非常的简单,只需要下载可执行文件,添加可执行权限并启动即可

$ wget https://s3.amazonaws.com/outline-releases/manager/linux/stable/Outline-Manager.AppImage

$ chmod +x Outline-Manager.AppImage

$ ./Outline-Manager.AppImage
Outline Manager is starting
libva error: vaGetDriverNameByIndex() failed with unknown libva error, driver_name = (null)
[42740:0925/174650.529715:ERROR:viz_main_impl.cc(186)] Exiting GPU process due to errors during initialization
Launching web app from outline://web_app/index.html?version=1.15.2&sentryDsn=https%3A%2F%2F9df8c810bf1b482d979da996e3e63c40%40o74047.ingest.sentry.io%2F215496
libva error: vaGetDriverNameByIndex() failed with unknown libva error, driver_name = (null)
[42774:0925/174651.006194:ERROR:viz_main_impl.cc(186)] Exiting GPU process due to errors during initialization
libva error: vaGetDriverNameByIndex() failed with unknown libva error, driver_name = (null)
[42800:0925/174651.310808:ERROR:gpu_memory_buffer_support_x11.cc(44)] dri3 extension not supported.
Checking for update
Generated new staging user ID: c5db7469-3a5b-5365-a374-7e29a6e0c71a
Update for version 1.15.2 is not available (latest version: 1.15.2, downgrade is disallowed).

  • 为安全起见,Outline Manager 不支持以 root 用户执行,请以普通用户身份执行

  • Outline Manager 依赖于 fuse,执行命令 sudo apt install fuse 安装

  • Outline VPN Server 依赖于 Docker 和 curl,请提前安装

Outline Manager 运行后会启动 UI

Outline VPN Server 部署

Outline 环境中,VPN Server 负责具体的 VPN 节点实现。要部署 VPN Server,选择合适的服务器环境,比如使用自己的本地服务器则选择 Set up Outline anywhere,然后根据提示在具体的 VPN Server 上部署程序即可

  1. 根据提示,执行以下命令,部署 VPN Server 环境程序

    # sudo bash -c "$(wget -qO- https://raw.githubusercontent.com/Jigsaw-Code/outline-server/master/src/server_manager/install_scripts/install_server.sh)"
    > Verifying that Docker is installed .......... OK
    > Verifying that Docker daemon is running ..... OK
    > Setting PUBLIC_HOSTNAME to external IP ...... OK
    > Creating persistent state dir ............... OK
    > Generating secret key ....................... OK
    > Generating TLS certificate .................. OK
    > Generating SHA-256 certificate fingerprint .. OK
    > Writing config .............................. OK
    > Starting Shadowbox .......................... OK
    > Starting Watchtower ......................... OK
    > Removing watchtower container ............... OK
    > Restarting watchtower ....................... OK
    > Waiting for Outline server to be healthy .... OK
    > Creating first user ......................... OK
    > Adding API URL to config .................... OK
    > Checking host firewall ...................... OK

    CONGRATULATIONS! Your Outline server is up and running.

    To manage your Outline server, please copy the following line (including curly
    brackets) into Step 2 of the Outline Manager interface:

    {"apiUrl":"https://66.26.90.25:50472/Q6XjXdbbVbetfAV0TK2cyw","certSha256":"67695819036A0FA4CE3C9E4AFAA0466D3C4BE4D9B04DBF7D8BA820FB379C0E4C"}

    If you have connection problems, it may be that your router or cloud provider
    blocks inbound connections, even though your machine seems to allow them.

    Make sure to open the following ports on your firewall, router or cloud provider:
    - Management port 50472, for TCP
    - Access key port 13279, for TCP and UDP

    根据提示 Management port 50472, for TCPAccess key port 13279, for TCP and UDP,防火墙放通对应的端口

    默认情况下,Management portAccess key port 使用随机端口,要使用自定义的固定端口,使用以下命令配置 VPN Server 环境

    bash install_server.sh --api-port 65530 --keys-port 65531

    如果在同一台主机上重复执行 install_server.sh,请删除持久化数据目录,默认为 /opt/outline/ ,否则可能出现重复部署后某些配置依然是旧的。

  2. 下载客户端程序,COPY ACCESS KEY 到客户端测试连接。

阅读全文 »

Certbot 是 Let’s Encrypt SSL 官方推荐的 ACME 协议客户端,它是一个 Python 程序,且包含模块化插件支持。Let’s Encrypt 的根证书浏览器支持广泛,且支持泛域名。但单个证书的有效期为 90 天,以防止滥用。

安装 Certbot

官方安装步骤参考

以下步骤演示在 Python3 环境中安装 Certbot 及其相关依赖

  1. 安装 certbot
    pip install certbot
  2. 申请证书时,要使用 DNS 方式验证域名所有权并且 DNS 使用 Cloudflare 的情况下,可以安装 certbot-dns-cloudflare 插件实现自动验证,参考以下命令安装 certbot-dns-cloudflare,此模块需要 cloudflare 模块的支持
    pip install cloudflare
    pip install certbot-dns-cloudflare
    安装完成后检查相关模块和版本。其中 cloudflare 版本需要最低为 2.3.1 [1]
    # pip list
    certbot 2.10.0
    certbot-dns-cloudflare 2.10.0
    cloudflare 2.19.2
    以上模块安装完成后,即可使用 certbot 申请域名证书,并支持 Cloudflare DNS 的自动验证。

基于 Cloudflare DNS 的自动验证申请域名证书

参考步骤安装 certbot 及 Cloudflare DNS 插件后 即可使用 certbot 自动请求 Cloudflare DNS 创建申请证书时需要的 DNS 记录自动完成域名归属权的验证过程。

certbot 支持的 Cloudflare 相关的参数如下

参数 说明 示例
--dns-cloudflare 使用 Cloudflare 的 DNS 插件自动验证域名归属权
--dns-cloudflare-credentials 请求 Cloudflare 的授权配置文件
--dns-cloudflare-propagation-seconds 请求 Cloudflare DNS 添加相关 DNS 记录后,让 ACME 服务等待多少秒再验证 DNS 记录。主要用来防止 DNS 记录添加后,缓存 DNS 服务器未来得及更新最新记录。
默认为 10

Cloudflare Credentials 说明

假设有 Cloudflare 账号的 Global API Key,则 Credentials 配置文件内容参考如下

cloudflare.ini
# Cloudflare API credentials used by Certbot
dns_cloudflare_email = [email protected]
dns_cloudflare_api_key = 0123456789abcdef0123456789abcdef01234

申请证书的具体命令如下,如果是第一次申请,需要根据提示填写自己的邮箱信息并同意许可协议,邮箱用于接受之后系统发送的错误或者域名证书过期等信息

certbot certonly \
--dns-cloudflare \
--dns-cloudflare-credentials ~/.secrets/certbot/cloudflare.ini \
--dns-cloudflare-propagation-seconds 60 \
-d example.com \
-d www.example.com

如果是非交互式环境,可以使用参数 --email [email protected]--agree-tos 自动绑定邮箱并同意许可

阅读全文 »

Shadowsocks 官网简介

基于 Python3 环境的 Shadowsocks 部署

执行以下命令之一安装 Shadowsocks (Python3 版本)

pip3 install git+https://github.com/shadowsocks/shadowsocks.git@master

pip3 install shadowsocks

配置 Shadowsocks

创建一个配置文件,比如放在 /etc/shadowsocks/config.json 目录下。配置文件的内容如下:

{
"server": "0.0.0.0",
"server_port": 8388,
"local_address": "127.0.0.1",
"local_port": 1080,
"password": "your_password",
"timeout": 300,
"method": "aes-256-cfb",
"fast_open": false
}

配置选项说明

  • server : 服务器监听的 IP 地址,0.0.0.0 表示监听所有接口。
  • server_port : 服务器监听的端口,客户端连接到这个端口。
  • password : 用于加密流量的密码,请设置一个强密码。
  • method : 加密方法。其他加密算法请参考官网
  • timeout : 超时时间(秒)。
  • fast_open : 如果启用 TCP Fast Open,请将其设置为 true,但需要内核支持。

启动 Shadowsocks 服务

使用以下命令启动 Shadowsocks 服务,该命令会以后台进程的方式启动 Shadowsocks:

ssserver -c /etc/shadowsocks/config.json -d start

常用选项

选项 说明 示例
-h, --help 打印帮助信息
-d [start / stop / restart ] 以 Daemon 方式(后台)运行
--pid-file Daemon 模式启动时的 PID 文件路径
--log-file Daemon 模式启动时日志文件路径
--user 运行服务的用户
-v, -vv verbose 模式
-q, -qq quite 模式
-c 配置文件路径 ssserver -c /etc/shadowsocks/config.json -d start
-s 指定服务端监听地址,默认为 0.0.0.0 。等同于配置文件中的 server
-p 指定服务端监听端口,默认为 8388 。等同于配置文件中的 server_port
-k 指定密码 。等同于配置文件中的 password
-m 加密方法,默认为 aes-256-cfb 。 等同于配置文件中的 method
-t 超时时间(单位为 ),默认 300s 。 等同于配置文件中的 timeout
--fast-open 启用 TCP_FASTOPEN,需要 Linux 3.7+
--workers workers 数量,Linux/Unix 可用
--forbidden-ip , 分割的 IP 列表,在此列表中的 IP 禁止连接,即黑名单
--manager-address 服务端 UDP 管理地址

为 Shadowsocks 配置 systemd services 文件

参考以下内容,为 Shadowsocks 配置 systemd services 文件

/etc/systemd/system/shadowsocks.service
[Unit]
Description=Shadowsocks Proxy Server
After=network.target

[Service]
ExecStart=/usr/local/bin/ssserver -c /etc/shadowsocks/config.json
Restart=on-failure

[Install]
WantedBy=multi-user.target

启用并启动 Shadowsocks 服务

sudo systemctl enable shadowsocks
sudo systemctl start shadowsocks

客户端连接

在客户端(如 Windows、macOS、iOS 或 Android)上,使用 Shadowsocks 客户端进行连接。

客户端配置

  • 服务器地址 : 填写你服务器的公网 IP。
  • 服务器端口 :填写 config.json 中的 server_port,如 8388
  • 密码 : 填写配置文件中的 password
  • 加密方法 : 选择 method 中配置的加密方法,如 aes-256-cfb

如果需要调试或查看运行日志,可以通过以下命令查看 Shadowsocks 的日志:

journalctl -u shadowsocks

ss 命令是一个查看 Linux 系统 socket 统计信息的工具,类似于 netstat,但是能显示更多的 TCP 和状态信息。

常用选项 ,可查看 man ss

选项 说明 示例
-h, --help 输出选项的简要说明
-V, --version 打印版本信息
-H, --no-header 不打印首行(Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
-n, --numeric 不对服务名进行解析,直接输出端口(数值类型)
-r, --resolve 尝试解析 IP 和 端口 为对应的名称,默认行为
-a, --all 列出正在监听的端口以及已经建立连接的端口
-l, --listening 仅列出正在监听的端口,默认不列出。
-m, --memory 显示 socket内存 使用情况
-p, --processes 显示使用此 socket 的进程
-s, --summary 显示简略的统计信息
-4, --ipv4 只显示 IPv4 相关的 socket
-6, --ipv6 只显示 IPv6 相关的 socket
-t, --tcp 只显示 TCP 相关 socket
-u, --udp 只显示 UDP 相关 socket

环境信息

  • Centos 7

automake

编译安装软件报错

error: require Automake 1.14, but have 1.13.4

Automake 版本不匹配,需要安装 Automake 1.14

$ rpm -qa | grep automake
automake-1.13.4-3.el7.noarch

以下步骤安装 automake-1.14.1

wget http://ftp.gnu.org/gnu/automake/automake-1.14.1.tar.gz
tar -xf automake-1.14.1.tar.gz
cd automake-1.14.1
./bootstrap.sh

以上步骤执行完成后,会生成 configure 可执行文件

./configure
make
make install

安装完成后,执行以下命令验证版本

$ automake --version
automake (GNU automake) 1.14.1
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv2+: GNU GPL version 2 or later <http://gnu.org/licenses/gpl-2.0.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Written by Tom Tromey <[email protected]>
and Alexandre Duret-Lutz <[email protected]>.

makeinfo

编译安装软件报错

makeinfo: command not found

makeinfo 命令不存在,执行以下命令安装

yum install texinfo

gcc

no acceptable C compiler found in $PATH

缺少 gcc 编译器,安装即可

yum install -y gcc

A compiler with support for C++11 language features is required

编译安装软件时报错

configure: error: *** A compiler with support for C++11 language features is required.

错误原因为 gcc 版本太低。查看当前 gcc 版本

$ gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-redhat-linux/4.8.5/lto-wrapper
Target: x86_64-redhat-linux
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-bootstrap --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-linker-build-id --with-linker-hash-style=gnu --enable-languages=c,c++,objc,obj-c++,java,fortran,ada,go,lto --enable-plugin --enable-initfini-array --disable-libgcj --with-isl=/builddir/build/BUILD/gcc-4.8.5-20150702/obj-x86_64-redhat-linux/isl-install --with-cloog=/builddir/build/BUILD/gcc-4.8.5-20150702/obj-x86_64-redhat-linux/cloog-install --enable-gnu-indirect-function --with-tune=generic --with-arch_32=x86-64 --build=x86_64-redhat-linux
Thread model: posix
gcc version 4.8.5 20150623 (Red Hat 4.8.5-44) (GCC)

安装 gcc-8.3.0

以下步骤演示安装 gcc-8.3.0 [1]

  1. 下载安装包,官方下载地址
    wget ftp://ftp.irisa.fr/pub/mirrors/gcc.gnu.org/gcc/releases/gcc-8.3.0/gcc-8.3.0.tar.gz
    tar -xf gcc-8.3.0.tar.gz
    cd gcc-8.3.0
  2. 编译安装。编译依赖 GMP 4.2+, MPFR 2.4.0+ and MPC 0.8.0+,需要先按照顺序安装这 3 个依赖。依赖安装参考: 安装 GMP安装 MPFR安装 MPC
    $ ./configure --prefix=/usr/local/gcc-8.3.0 --disable-multilib
    $ make
    $ make install
  3. 安装完成后,需要更新系统标准库 查看当前系统使用的 gcc 库文件,可以看到版本为 libstdc++.so.6.0.19
    $ ls /usr/lib64/libstdc++.so.6
    libstdc++.so.6 libstdc++.so.6.0.19

    $ ls /usr/lib64/libstdc++.so.6 -l
    lrwxrwxrwx 1 root root 19 May 30 08:05 /usr/lib64/libstdc++.so.6 -> libstdc++.so.6.0.19
    执行以下操作,更新 libstdc++.so.6 到最新安装的版本
    $ rm -rf /usr/lib64/libstdc++.so.6

    $ ln -s /usr/local/gcc-8.3.0/lib64/libstdc++.so.6.0.25 /usr/lib64/libstdc++.so.6

    $ ls /usr/lib64/libstdc++.so.6 -l
    lrwxrwxrwx 1 root root 46 Jun 9 09:31 /usr/lib64/libstdc++.so.6 -> /usr/local/gcc-8.3.0/lib64/libstdc++.so.6.0.25

安装 GMP

安装包下载地址

wget ftp://gcc.gnu.org/pub/gcc/infrastructure/gmp-6.1.0.tar.bz2
tar -jxvf gmp-6.1.0.tar.bz2
cd gmp-6.1.0
./configure
make && make install

安装 MPFR

安装包下载地址

wget ftp://gcc.gnu.org/pub/gcc/infrastructure/mpfr-3.1.4.tar.bz2
tar -jxvf mpfr-3.1.4.tar.bz2
cd mpfr-3.1.4
./configure
make && make install

安装 MPC

安装包下载地址

wget ftp://gcc.gnu.org/pub/gcc/infrastructure/mpc-1.0.3.tar.gz
tar -zxvf mpc-1.0.3.tar.gz
cd mpc-1.0.3
./configure
make && make install
阅读全文 »

环境信息

  • Ubuntu 24.04.1 LTS (Noble Numbat)
  • nftables v1.0.9 (Old Doc Yak #3)

配置错误

Statement after terminal statement has no effect

有以下配置:

ip daddr 127.0.0.11 jump DOCKER_OUTPUT counter;

meta l4proto tcp ip daddr 127.0.0.11 tcp dport 53 dnat to 127.0.0.11:45143 counter;

加载配置时报错: Error: Statement after terminal statement has no effect

错误原因nftables 规则中在 终止语句(terminal statement(如 jumpdnat)后添加的语句(如 counter)没有作用,因为 jumpdnat 语句已经处理了数据包,不会再执行后续的语句。

nftables 中,终止语句(terminal statement 是那些一旦执行后就结束了该数据包的处理,例如 jumpacceptdropdnatsnat 等。因为这些语句会决定数据包的最终去向,所以在这些语句后面再添加如 counter 这样的语句是无效的。

解决方法 : 要正确配置计数器,你需要 counter 放在终止语句 之前,这样在执行 jumpdnat 之前,数据包会先经过计数器。

ip daddr 127.0.0.11 counter jump DOCKER_OUTPUT;

meta l4proto tcp ip daddr 127.0.0.11 tcp dport 53 counter dnat to 127.0.0.11:45143;

syntax error

一次性配置多个端口

假如要在一个规则中同时放通 HTTP 和 HTTPS (80443 端口),以下是错误语句

# nft insert inet filter input handle 11 tcp dport 80,443 counter accept comment \"for nginx\"
Error: syntax error, unexpected inet, expecting rule
insert inet filter input handle 11 tcp dport 80,443 counter accept comment for nginx
^^^^

nftables 中,多个端口 在指定时不能直接用逗号分隔。对于多个端口,应该使用集合({})的语法来指定。以下为正确语法

# nft insert rule inet filter input handle 11 tcp dport { 80,443 } counter accept comment \"for nginx\"

注意: 使用 集合{})语法时要注意其中的空格,{ 80,443 } 是正确格式,如果写成 {80,443} 则是错误格式

cmd 中添加注释报错

使用以下语句添加规则报错:

# nft insert rule inet filter input handle 11 tcp dport { 80,443 } counter accept comment "for nginx" 
Error: syntax error, unexpected string, expecting end of file or newline or semicolon
insert rule inet filter input handle 11 tcp dport { 80,443 } counter accept comment for nginx
^^^^^

正确格式如下:

# nft insert rule inet filter input handle 11 tcp dport { 80,443 } counter accept comment \"for nginx\"

注意: 在 cmd 中交互式操作时,注释中使用的 双引号("" 要使用 转义(\

阅读全文 »

环境信息

  • Centos 7.9.2009
  • docker-ce-19.03.15

Docker 网络模式

Bridge 模式

bridge 模式是 docker 的默认网络模式,不使用 --network 参数,就是 bridge 模式。

当 Docker 进程启动时,会在主机上创建一个名为 docker0 的虚拟网桥,默认主机上启动的 Docker 容器会连接到这个虚拟网桥上。

容器启动时,docker 会从 docker0 网桥的子网中分配一个 IP 地址给容器中的网卡。大体流程为在主机上创建一个 `veth pair`,Docker 将 veth pair 的一端放在容器中,命名为 eth0 并配置 IP,网关,路由等信息,将 veth pair 的另一端加入 docker0 网桥。

通过这种方式,主机可以跟容器通信,容器之间也可以相互通信。

Host 模式

如果启动容器的时候使用 host 模式,那么这个容器将不会获得一个独立的 Network Namespace,而是和宿主机一样在 Root Network Namespace,容器中看到的网络方面的信息和宿主机一样,容器使用的网络资源在整个 Root Network Namespace 不能出现冲突。容器将不会虚拟出自己的网卡,配置自己的 IP 等,而是使用宿主机的 IP 和端口,主机名也是使用宿主机的。但是,容器的其他方面,如文件系统、进程列表等还是和宿主机隔离的。

host 模式下的容器可以看到宿主机上的所有网卡信息,可以直接使用宿主机 IP 或主机名与外界通信,无需额外的 NAT,也无需通过 Linux bridge 进行转发或者数据包的封装,可以访问主机上的其他任一容器

使用如下命令参数启动 host 网络模式的容器

docker run --network host --name test1 -p 80:80 -d -it centos:centos7.9.2009

host 模式的容器,没有自己的 network namespace,在 root network namespace 中。进入测试容器 test1,查看网卡、 IP 信息及端口、主机名信息,会看到和宿主机一样的信息。

$ ip 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
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:e7:c0:27 brd ff:ff:ff:ff:ff:ff
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN mode DEFAULT group default
link/ether 02:42:f2:1b:dc:ea brd ff:ff:ff:ff:ff:ff

$ 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
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 00:0c:29:e7:c0:27 brd ff:ff:ff:ff:ff:ff
inet 192.168.142.10/24 brd 192.168.142.255 scope global noprefixroute ens33
valid_lft forever preferred_lft forever
inet6 fe80::20c:29ff:fee7:c027/64 scope link
valid_lft forever preferred_lft forever
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
link/ether 02:42:f2:1b:dc:ea brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
valid_lft forever preferred_lft forever

$ [root@test1 /]# netstat -anutp
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN -
tcp 0 0 0.0.0.0:81 0.0.0.0:* LISTEN 124/nginx: master p
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN -
tcp 0 36 192.168.142.10:22 192.168.142.1:61396 ESTABLISHED -
tcp6 0 0 :::80 :::* LISTEN -
tcp6 0 0 :::81 :::* LISTEN 124/nginx: master p
tcp6 0 0 :::22 :::* LISTEN -

host 模式的缺点

  • 容器没有自己的 network namespace ,网络和宿主机或其他使用 host 模式的容器未隔离,容易出现资源冲突,比如同一个宿主机上,使用 host 模式的容器中启动的端口不能相同。

None 模式

使用 none 模式,Docker 容器拥有自己的 Network Namespace,但是,系统并不为 Docker 容器进行任何网络配置。也就是说,这个 Docker 容器没有网卡(lo 回环网卡除外)、IP、路由等信息。需要我们自己为 Docker 容器添加网卡、配置 IP 等。

参考以下命令创建 none 模式的容器

docker run --network none --name test-none -p 82:80 -d -it centos7:my

容器创建后,进入容器中,查看网卡和 IP 等信息,容器中默认只存在 lo 网卡,不存在其他网卡

$ 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

$ ip 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

以下操作演示手动为容器配置网络

  1. 创建 veth pair

    ip link add veth0 type veth peer name veth0_p
  2. veth pair 的一端 veth0 放入 docker 默认的网桥 docker0,另一端 veth0_p 放入容器中

    首先使用命令 docker inspect test-none | grep "Pid" 找到容器对应的 PID,此处为 84040,根据此 PID 将 veth 的一端放入容器的 network namespace 中

    ip link set dev veth0 master docker0

    ip link set dev veth0 up

    ip link set veth0_p netns 84040

    在宿主机上面检查 veth0,确定其已经加入网桥 docker0,并且 veth0_p 已不在 root network namespace

    $ ip 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
    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:e7:c0:27 brd ff:ff:ff:ff:ff:ff
    3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN mode DEFAULT group default
    link/ether 02:42:f2:1b:dc:ea brd ff:ff:ff:ff:ff:ff
    12: veth0@if11: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master docker0 state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
    link/ether 16:7f:98:d8:9d:dc brd ff:ff:ff:ff:ff:ff link-netnsid 0

    重新进入容器,检查网卡信息,可以看到容器中已经有了网卡 veth0_p,状态为 DOWN

    $ 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
    11: veth0_p@if12: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether be:f1:94:9f:b8:c9 brd ff:ff:ff:ff:ff:ff link-netnsid 0 promiscuity 0
    veth addrgenmode eui64 numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535
  3. 为容器中的网卡配置 IP 及网关等信息

    为了能在宿主机对容器的 network namespace 进行操作,首先需要将容器的 network namespace 暴露出来,之后可以在宿主机通过 network namespace 名称(此处为 84040,可以自定义)操作 network namespaceLinux network namespace 参考

    $ ln -s /proc/84040/ns/net /var/run/netns/84040
    $ ip netns ls
    84040 (id: 0)

    通过 network namespace 名称(此处为 84040)配置容器中网卡的 IP 地址信息

    ip netns exec 84040 ip link set dev veth0_p name eth0
    ip netns exec 84040 ip link set dev eth0 up

    ip netns exec 84040 ip add add 172.17.0.10/16 dev eth0

    ip netns exec 84040 ip route add default via 172.17.0.1

    进入容器检查网络信息

    $ 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
    15: eth0@if16: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 7e:36:b3:20:a1:8c brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.17.0.10/16 scope global eth0
    valid_lft forever preferred_lft forever

    $ ip route show
    default via 172.17.0.1 dev eth0
    172.17.0.0/16 dev eth0 proto kernel scope link src 172.17.0.10

    进入容器测试网络连接

    $ ping 8.8.8.8
    PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
    64 bytes from 8.8.8.8: icmp_seq=1 ttl=127 time=37.4 ms
    64 bytes from 8.8.8.8: icmp_seq=2 ttl=127 time=37.0 ms
    ^C
    --- 8.8.8.8 ping statistics ---
    2 packets transmitted, 2 received, 0% packet loss, time 1000ms
    rtt min/avg/max/mdev = 37.047/37.234/37.422/0.269 ms
阅读全文 »

环境信息

  • Centos 7.9.2009
  • docker-ce-19.03.15
  • docker-20.10.9

Docker 安装

yum 安装 docker

安装 yum 源,docker官方 centos 安装文档

yum install -y yum-utils
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

安装 docker

yum install docker-ce docker-ce-cli containerd.io docker-compose-plugin

yum 离线安装 docker

参考链接下载rpm安装包

wget https://download.docker.com/linux/centos/7/x86_64/stable/Packages/docker-ce-19.03.15-3.el7.x86_64.rpm
wget https://download.docker.com/linux/centos/7/x86_64/stable/Packages/docker-ce-cli-19.03.15-3.el7.x86_64.rpm
wget https://download.docker.com/linux/centos/7/x86_64/stable/Packages/containerd.io-1.4.13-3.1.el7.x86_64.rpm
wget https://download.docker.com/linux/centos/7/x86_64/stable/Packages/docker-compose-plugin-2.3.3-3.el7.x86_64.rpm

安装 docker

yum localinstall -y containerd.io-1.4.13-3.1.el7.x86_64.rpm \
docker-ce-cli-19.03.15-3.el7.x86_64.rpm \
docker-ce-19.03.15-3.el7.x86_64.rpm \
docker-compose-plugin-2.3.3-3.el7.x86_64.rpm

以上 2 条命令可以使用以下 1 条命令完成

yum localinstall -y https://download.docker.com/linux/centos/7/x86_64/stable/Packages/docker-ce-19.03.15-3.el7.x86_64.rpm \
https://download.docker.com/linux/centos/7/x86_64/stable/Packages/docker-ce-cli-19.03.15-3.el7.x86_64.rpm \
https://download.docker.com/linux/centos/7/x86_64/stable/Packages/containerd.io-1.4.13-3.1.el7.x86_64.rpm \
https://download.docker.com/linux/centos/7/x86_64/stable/Packages/docker-compose-plugin-2.3.3-3.el7.x86_64.rpm

启动docker

systemctl enable docker --now
阅读全文 »

iptables 的底层实现是 netfilternetfilter 的架构是在整个网络流程(TCP/IP 协议栈)的若干位置放置一些钩子,并在每个钩子上挂载一些处理函数进行处理。

IP 层的 5 个钩子点的位置,对应就是 iptables 的 5 条内置链,分别是

  • PREROUTING
  • FORWARD
  • INPUT
  • OUTPUT
  • POSTROUTING


当网卡收到一个网络报文送达协议栈时,最先经过的 netfilter 钩子是 PREROUTING,此处常见的钩子函数是 目的地址转换 (DNAT)。无论 PREROUTING 是否存在钩子处理网络数据包,下一步内核都会通过 查询本地路由表 决定这个数据包的流向

  • 如果是发送给本地进程,则进入 INPUT 链传给本地进程
  • 如果是发送给其他机器(或者其他 network namespace),则经过 netfilterFORWARD 钩子传送出去,相当于将本地机器当作路由器

所有马上要发送到网络协议栈之外的数据包,都会经过 POSTROUTING 钩子,这里常见的处理函数是 源地址转换(SNAT) 或者 源地址伪装(Masquerade, 简称 Masq)

除了 5 条内置的链,iptables 还有 5 张表,这 5 张表主要是用来给 iptables 中的规则(rule)分类,系统中所有的 iptables 规则都被划分到不同的表集合中。5 张表分别为

  • raw - iptables 是有状态的,即 iptables 对数据包有连接追踪 (connection trackong) 机制,而 raw 可以用来去除这种追踪机制
  • mangle - 用于修改数据包的 IP 头信息
  • nat - 用于修改数据包的源或者目的地址
  • filter - 用于控制到达某条链上面的数据包是继续放行、直接丢弃(drop)、或拒绝(reject)
  • security - 用于在数据包上面应用 SELinux

表是有优先级的,5 张表的优先级从高到低是: rawmanglenatfiltersecurityiptables 不支持自定义表。不是每个链上都能挂表,iptables 表与链的对应关系如下图

- PREROUTING FORWARD INPUT OUTPUT POSTROUTING
raw Y N N Y N
mangle Y Y Y Y Y
nat (SNAT) N N Y N Y
nat (DNAT) Y N N Y N
filter N Y Y Y N
security N Y Y Y N

iptables 表和链的工作流程图如下

iptables 命令

常用选项说明

选项 说明 示例
-F ,--flush 清除所有规则,默认规则除外
-P ,--policy 设置默认规则
-t ,--table 指定要操作的表,默认为 filter iptables -t nat -P INPUT ACCEPT
--list ,-L [chain [rulenum]] 列出(指定的链或所有链)的规则 iptables -t nat -L -v -n --line-numbers
--verbose ,-v verbose mode
--numeric ,-n 不解析协议和端口号,以数字的形式显示
--line-numbers 显示规则的行号,可以根据行号对具体的规则进行操作
--jump ,-j 匹配的规则的处理 target iptables -A INPUT -j LOG
--append ,-A chain 像指定的链中追加规则 -A INPUT -i lo -j ACCEPT
--insert ,-I chain [rulenum] 向指定的链中指定的位置插入规则 iptables -I INPUT 10 -p tcp --dport 80 -j ACCEPT
--delete ,-D chain rulenum 删除指定链中的指定位置的规则 iptables -D INPUT 10
--replace ,-R chain rulenum 更新指定链中的指定位置的规则
-S, --list-rules [chain] 按照类似 iptables-save 的输出打印规则
阅读全文 »

环境信息

  • Centos 7

logrotate 程序是一个日志文件管理工具。用于分割日志文件,压缩转存、删除旧的日志文件,并创建新的日志文件

logrotate 是基于 crond 来运行的,其脚本是 /etc/cron.daily/logrotate,日志轮转是系统自动完成的。
实际运行时,logrotate 会调用配置文件 /etc/logrotate.conf
/etc/cron.daily/logrotate 文件内容如下:

/etc/cron.daily/logrotate
#!/bin/sh

/usr/sbin/logrotate -s /var/lib/logrotate/logrotate.status /etc/logrotate.conf
EXITVALUE=$?
if [ $EXITVALUE != 0 ]; then
/usr/bin/logger -t logrotate "ALERT exited abnormally with [$EXITVALUE]"
fi
exit 0

可以执行以下命令手动执行日志切割:

logrotate -f /etc/logrotate.conf

以下命令可以检测配置文件是否正确:

logrotate -d /etc/logrotate.conf
阅读全文 »

systemd 是一种用于 Linux 操作系统的系统和服务管理器。它被广泛应用于许多现代 Linux 发行版中,如 CentOS、Fedora、Ubuntu 等。systemd 旨在替代传统的 SysVLSB init 系统,并提供更强大、灵活的系统启动和服务管理功能。

systemd 的关键概念和组件

  • Unit 文件

    • systemd 使用单元(Unit)文件来描述系统资源。常见的单元类型包括:
      • Service Unit (*.service) : 用于定义和管理服务。
      • Target Unit (*.target) : 用于分组和同步一组单元的启动,如 multi-user.target
      • Timer Unit (*.timer) : 用于定时任务,相当于 cron 的替代品。
      • Socket Unit (*.socket) :用于管理网络或 IPC 套接字。
      • Mount Unit (*.mount) : 用于定义挂载点。
      • Path Unit (*.path) : 监控文件或者目录的变化。当监控的文件或目录发生变化时,可以触发相应的 service 单元。
    • 单元(Unit)文件通常存储在以下目录
      • `/etc/systemd/system/ :系统管理员定义的单位文件,优先级较高。
      • /lib/systemd/system/ :发行版提供的单位文件,优先级较低。
      • /run/systemd/system/ :运行时生成的单位文件,临时的。
  • Target 文件

    • systemd 使用 target 取代传统的运行级别(runlevel)。常见的目标包括:
      • multi-user.target : 相当于传统的运行级别 3,支持多用户、无图形界面。
      • graphical.target : 相当于传统的运行级别 5,支持多用户和图形界面。
      • rescue.target : 相当于传统的单用户模式,提供基本的系统恢复环境。
  • 日志管理

    • systemd 使用 `journald` 来管理系统日志。你可以使用 journalctl 命令查看日志
  • 服务间的依赖关系

    • systemd 处理服务间的依赖关系。你可以通过 After=Before=Requires= 等指令在单元文件中定义这些依赖。

systemd 的优势:

  • 并行启动systemd 可以并行启动服务,减少启动时间。
  • 依赖管理 : 能够自动处理服务间的依赖关系,保证系统按需启动服务。
  • 日志记录systemd 的日志管理功能强大,提供了统一的接口查看和分析日志。
  • 定时任务管理 : 通过 timer 单元文件可以灵活地配置定时任务,作为 cron 的替代方案。
阅读全文 »

Grafana 是一款用 GO 语言开发的开源数据可视化工具,可以做数据监控和数据统计,带有告警功能。

基础概念

组织(Organization) 与用户(User)

Organization 相当于一个 Namespace,一个 Organization 完全独立于另一个 Organization,包括 datasourcedashboard 等,创建一个 Organization 就相当于打开了一个全新的视图,所有的 datasourcedashboard 等都需要重新创建。一个用户(User) 可以属于多个 Organization。

User 是 Grafana 里面的用户,用户可以有以下 角色

  • admin - 管理员权限,可以执行任何操作。
  • editor - p不可以创建用户不可以新增 Datasource可以创建 Dashboard**
  • viewer - 仅可以查看 Dashboard
  • read only editor - 允许用户修改 Dashboard,但是 不允许保存

数据源 Datasource

Grafana 中操作的数据集、可视化数据的来源

Dashboard

在 Dashboard 页面中,可以组织可视化数据图表。

  • Panel - 在一个 Dashboard 中,Panel 是最基本的可视化单元。通过 Panel 的 Query Editor 可以为每一个 Panel 添加查询的数据源以及数据查询方式。每一个 Panel 都是独立的,可以选择一种或者多种数据源进行查询。一个 Panel 中可以有多个 Query Editor 来汇聚多个可视化数据集
  • Row - 在 Dashboard 中,可以定义一个 Row,来组织和管理一组相关的 Panel

Variables

在 Dashboard 的设置页面中,有 Variables 页面,在其中可以为 Dashboard 配置变量,之后可以在 Panel 的 Query Editor 中使用这些预定义的变量。变量的值也可以是通过表达式获取的值。也可以在 Panel 的标题中使用变量

例如以下 Variables 配置

Node    label_values(kubernetes_io_hostname)

在 Dashboard 中定义了这些变量后,可以在 Panel 的 Query Editor 中使用,在 Query Editor 中使用了 Variables 中定义的变量后,在 Dashboard 的顶部下拉菜单中可以选择预定义的变量的值(需要在定义 Variables 时配置 Show on dashboardLabel and Value 以使在 Dashboard 顶部显示下拉菜单),Panel 中的 Query 表达式就会使用这些变量的值进行计算以及显示图表。

阅读全文 »

环境信息

  • Python 3.10.12

certificate verify failed: unable to get local issuer certificate

报错信息如下:

ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1007)
...
urllib.error.URLError: <urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1007)>

问题原因 : 本地 CA 证书不存在

解决方法

  1. 查看默认证书位置
    >>> import ssl
    >>> print(ssl.get_default_verify_paths())
    DefaultVerifyPaths(cafile=None, capath='/usr/local/openssl/ssl/certs', openssl_cafile_env='SSL_CERT_FILE', openssl_cafile='/usr/local/openssl/ssl/cert.pem', openssl_capath_env='SSL_CERT_DIR', openssl_capath='/usr/local/openssl/ssl/certs')

    根据输出内容,可以看到 Python 使用的 openssl 位于 /usr/local/openssl/,CA 证书路径为 /usr/local/openssl/ssl/cert.pem,检查 CA 证书路径,发现 CA 证书不存在
    $ cd /usr/local/openssl/ssl/
    $ ls
    certs ct_log_list.cnf ct_log_list.cnf.dist misc openssl.cnf openssl.cnf.dist private
  2. 下载 CA 证书文件
    wget http://curl.haxx.se/ca/cacert.pem --no-check-certificate
    mv cacert.pem cert.pem
    下载 CA 证书文件后,重新尝试,SSl 连接正常。

can’t start new thread

环境信息

  • Docker 1.13
  • Python3.9

在 Docker 中运行 python 后,使用 pip 报错 RuntimeError: can't start new thread

# pip install --upgrade pip
Requirement already satisfied: pip in /usr/local/lib/python3.9/site-packages (23.0.1)
Collecting pip
Downloading pip-23.2.1-py3-none-any.whl (2.1 MB)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 0.0/2.1 MB ? eta -:--:--ERROR: Exception:
Traceback (most recent call last):
File "/usr/local/lib/python3.9/site-packages/pip/_internal/cli/base_command.py", line 160, in exc_logging_wrapper
status = run_func(*args)
File "/usr/local/lib/python3.9/site-packages/pip/_internal/cli/req_command.py", line 247, in wrapper
return func(self, options, args)

...
File "/usr/local/lib/python3.9/site-packages/pip/_internal/operations/prepare.py", line 107, in get_http_url
from_path, content_type = download(link, temp_dir.path)
File "/usr/local/lib/python3.9/site-packages/pip/_internal/network/download.py", line 147, in __call__
for chunk in chunks:
File "/usr/local/lib/python3.9/site-packages/pip/_internal/cli/progress_bars.py", line 52, in _rich_progress_bar
with progress:
File "/usr/local/lib/python3.9/site-packages/pip/_vendor/rich/progress.py", line 1169, in __enter__
self.start()
File "/usr/local/lib/python3.9/site-packages/pip/_vendor/rich/progress.py", line 1160, in start
self.live.start(refresh=True)
File "/usr/local/lib/python3.9/site-packages/pip/_vendor/rich/live.py", line 132, in start
self._refresh_thread.start()
File "/usr/local/lib/python3.9/threading.py", line 899, in start
_start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread

[notice] A new release of pip is available: 23.0.1 -> 23.2.1
[notice] To update, run: pip install --upgrade pip

问题原因 Docker 版本太低,升级版本到 18.06 以上。参考说明

阅读全文 »

在 Ubuntu 上安装软件包主要通过使用 apt 命令来完成。apt 是高级包装工具(Advanced Package Tool)的缩写,提供了一个易用的命令行界面,用于处理软件包的安装、更新和删除等操作。

环境信息

  • Ubuntu 22

apt

查看软件包信息

  • 查看系统已安装的软件包

    apt list --installed

    apt list 列出系统上所有可用的软件包,包括已安装的软件包可供安装的软件包

  • 列出特定的软件包

    apt list <package-name>
  • 搜索特定软件包是否已安装

    apt list --installed  <package-name>
  • 查看软件包的依赖关系

    apt depends <package_name>

下载软件包

  • 下载软件包但不安装
    apt download <package_name>

安装软件包

  • 更新软件包列表。在安装新软件包之前,最好先更新本地软件包列表,以确保你安装的是最新版本的软件包。

    sudo apt update

    此命令会从配置的源中检索新的软件包列表。

  • 安装软件包。安装软件包的基本命令格式为:

    sudo apt install <package_name>
  • 安装特定版本的软件包

    如果你需要安装软件包的特定版本,可以通过指定版本号来完成安装。首先,使用 apt policy 命令查找可用版本

    apt policy <package_name>

    然后,安装特定版本的软件包

    sudo apt install <package_name>=<version>

    sudo apt install nginx=1.18.0-0ubuntu1
  • 安装推荐的软件包。

    当安装某些软件包时,APT 可能会建议安装一些推荐的软件包以增强功能。默认情况下,apt install 命令会安装推荐的软件包。 如果你不想安装推荐的软件包,可以使用 --no-install-recommends 选项

    sudo apt install --no-install-recommends <package_name>

卸载软件包

  • 卸载软件包但保留配置文件

    sudo apt remove <package_name>
  • 卸载软件包并删除配置文件。如果相关目录不为空,将不会删除,会输出提示

    sudo apt purge <package_name>

    或者

    sudo apt remove --purge <package_name>
  • 清理未使用的依赖包

    当你卸载一个软件包时,它可能会留下一些不再需要的依赖软件包。为了清理这些不再使用的依赖,可以执行:

    sudo apt autoremove

    这个命令会检查并自动删除那些被安装为其他软件包依赖但现在不再被任何已安装软件包需要的软件包。

dpkg

列出系统上已安装的软件包

dpkg -l

查找文件所属的软件包

dpkg -S /path/to/file

APT 仓库管理

APT 通过读取配置文件(主要是 /etc/apt/sources.list/etc/apt/sources.list.d/*.list)来获取软件包仓库(repository)的信息。

APT 的软件源配置文件是 /etc/apt/sources.list ,此外还可以包含 /etc/apt/sources.list.d/ 目录下的 .list 文件。这些文件定义了 APT 从哪里下载软件包和更新信息。

一个典型的 sources.list 条目格式如下:

deb [options] url distribution component1 component2 component3

  • deb:表示这是一个二进制软件包的仓库,对应的 deb-src 表示源代码仓库。
  • options:可选项,例如可以指定架构。
  • url:仓库的 URL。
  • distribution:发行版的代号,如 focalbuster 等。
  • component :仓库中的组成部分,如 mainrestricted 等。

Repository 的类型

在 APT 的上下文中,软件包仓库是网络或本地的存储位置,它们存储了软件包及其元数据。主要有以下几种类型的仓库:

  • Main:官方支持的免费软件。
  • Universe:社区维护的免费软件。
  • Restricted:官方支持的非自由软件。
  • Multiverse:非自由软件,不包括官方支持。

添加新的软件源

要添加新的软件源,你可以直接编辑 sources.list 文件或在 sources.list.d/ 目录下创建一个新的 .list 文件。例如,添加一个新的 PPA(Personal Package Archive):

sudo add-apt-repository ppa:<repository_name>

这个命令不仅会添加软件源,还会自动导入仓库的公钥,确保软件包的安全性。

删除软件源

要删除软件源,可以直接编辑 sources.list 文件或删除 sources.list.d/ 目录下相应的 .list 文件。之后,运行 sudo apt update 来更新软件包列表。

Linux X Window System

早期的 Linux 桌面都是基于来自 X.Org Foundation(http://www.x.org) 的 X Window System 的接口。一个 X.Org 的替代者是 Wayland (http://wayland.freedesktop.org)。

X Window System(简称 X)在 Linux 之前就存在,甚至早于 Microsoft Windows,它是一个轻量的、基于网络的桌面框架。

X Window System 是一种 Client/Server 模型。X Server 运行于本地操作系统中,为屏幕(Screen)、鼠标(Mouse)、键盘(Keyboard)提供对外的接口,X Client 可以在本地或者任何基于网络的远端系统上面运行。

X Server 本身只提供了一个简单的灰色背景和一个 X 型鼠标光标,没有菜单、面板、图标等,如果只是单纯的启动 X Client 展示 X Server 的内容,它展示的内容中不会包含 可以移动的边框、最大化、最小化按钮以及关闭窗口的按钮等 ,这些特性是由 Window Manager 提供的。

Window Manager 添加了可以操作程序的很多特性,如菜单、边框、常用按钮等。

Linux 中常见的桌面环境包括:

  • GNOME : 最初是为了模仿 MacOS 桌面
    • Gnome 2
    • Gnome 3 : 完全和 Gnome 2 的设计思路和理念不同,是一个全新的版本
  • K Desktop Environment (KDE) : 模拟了 Microsoft Windows 桌面
  • Xfce : 第一个轻量版的桌面环境,可以在系统资源(CPU,Mem)较少的环境中运行
  • LXDE : The Lightweight X11 Desktop Environment. 是一个高性能、节能的桌面环境。

Gnome3 相关常用操作

Gnome 3 提供了很多可用的插件来满足不同的需求,并提供了工具 Gnome Tweaks 用于调整 Gnome 的配置

Gnome Shell Extensions 可以控制 Gnome 桌面的外形和行为方式。GNOME Shell Extensions site (http://extensions.gnome.org)

查看 Gnome 版本

方法 1:通过设置查看

  1. 打开 “设置”:

    点击屏幕左下角的 “显示应用程序” 按钮(或按 Super 键,也就是通常的 Windows 键)。
    输入 Settings设置,然后点击出现的应用图标。
    查看 “关于” 信息:

  2. 在左侧面板中,向下滚动并选择 “关于”(About)。
    在“关于”页面中,你会看到 GNOME 版本信息以及其他系统详细信息。

方法 2:通过终端查看

你也可以通过终端命令查看 GNOME 版本:

  1. 打开终端:

    Ctrl + Alt + T 打开终端。

  2. 使用以下命令

    $ gnome-shell --version
    GNOME Shell 42.9

隐藏 Gnome 桌面顶部的工具栏

版本信息

  • Ubuntu 22.04.4 LTS (Jammy Jellyfish)
  • Gnome Shell 42.9

参考以下步骤:

  1. 安装 gnome-shell-extension-manager
    sudo apt-get install gnome-shell-extension-manager

  2. 打开 Extension-Manager
  3. 点击 Browse,搜索 hidetopbar 这个插件并安装(注意选择 Downloads!!,要不然搜不到插件

安装好了 hidetopbar 这个插件之后,上方的任务栏/状态栏 在窗口全屏时就会自动隐藏Super 键或者窗口非全屏时会重新显示

阅读全文 »

环境信息

  • Python 3.11.2

安装

pip install requests

常见用法

get 请求

get 请求及响应中常用的属性

>>> r = requests.get('https://csms.tech')
>>> dir(r)
[..., 'content', 'cookies', 'elapsed', 'encoding', 'headers', 'history',
'is_permanent_redirect', 'is_redirect', 'iter_content', 'iter_lines',
'json', 'links', 'next', 'ok', 'raise_for_status', 'raw', 'reason',
'request', 'status_code', 'text', 'url']

带参数的 get 请求

要在 get 请求中携带请求参数,可以使用以下方法

>>> help(requests.get)
get(url, params=None, **kwargs)
Sends a GET request.

:param url: URL for the new :class:`Request` object.
:param params: (optional) Dictionary, list of tuples or bytes to send
in the query string for the :class:`Request`.
:param \*\*kwargs: Optional arguments that ``request`` takes.
:return: :class:`Response <Response>` object
:rtype: requests.Response

>>> params = {'k1': 'v1', 'k2': 'v2'}
>>> r = requests.get('https://csms.tech', params=params)

# 设置请求头
>>> headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"}
>>> response = requests.get("https://csms.tech", params = params, headers = headers)

get 方法本质上是通过创建了一个 requests.Request 对象,因此 **kwargs 可用的值可以通过查看 requests.Request 的帮助信息。

>>> help(requests.Request)
阅读全文 »

环境信息

  • Selenium > 4.0

Selenium 是一个用于自动化 Web 浏览器操作的工具,可以用于模拟用户与网站的交互。

使用 pip 安装 Selenium 库

pip install selenium

Selenium 需要一个 WebDriver 来控制不同的浏览器。可以根据要使用的浏览器下载相应的 WebDriver。以下是一些常见的浏览器和对应的WebDriver下载链接:

下载 WebDriver 并确保它在系统路径中可用。WebDriver 和浏览器具有版本对应关系,要确保版本匹配

selenium 常见用法总结

本示例中以 Chrome 浏览器为例。

  • 创建一个浏览器实例,并请求指定的页面

    from selenium import webdriver
    from selenium.webdriver.common.by import By

    driver = webdriver.Chrome()

    driver.get("https://www.example.com")
  • 关闭当前浏览器窗口

    driver.close()
  • 最大化浏览器窗口

    driver.maximize_window()
  • 后退

    driver.back()
  • 前进

    driver.forward()
  • 刷新页面

    driver.refresh()
  • 关闭浏览器

    driver.quit()
    阅读全文 »

2Captcha 是一个验证码自动识别服务商。

验证码可以是含有必填扭曲文字的图片,也可以由不同图片组成,用户需从中选出符合特定条件的图片。这些操作是为了证明用户不是机器人。

环境信息

  • Python 3
  • 2captcha-python v1.2.8 [1]

2captcha 安装配置

2captcha 安装

参考官网安装文档 安装 Python3 模块

pip3 install 2captcha-python

使用简介

调用 2captcha 需要注册并使用 2captcha 提供的 API 密钥。

以下代码示例返回滑块类型的验证结果:


from twocaptcha import TwoCaptcha

# Initialize 2Captcha solver
config = {
'server': '2captcha.com',
'apiKey': 'ef5beb9c280ce7452183',
'defaultTimeout': 120,
'recaptchaTimeout': 600,
'pollingInterval': 10,
}

solver = TwoCaptcha(**config)

result = solver.coordinates(
'background_img.png',
hintImg='slider_img.png',
hintText="向右滑动填充拼图",
)
print(f'Captcha solved: {result}')

存在的问题

按照以上代码示例,针对相同的图片,每次请求返回的结果都不一样。2Captcha 针对滑块验证成功率太低,基本不可用。

Captcha solved: {'captchaId': '77043576230', 'code': 'coordinates:x=286,y=41'}

Captcha solved: {'captchaId': '77043579057', 'code': 'coordinates:x=276,y=45'}

Captcha solved: {'captchaId': '77043582438', 'code': 'coordinates:x=281,y=55'}

要缓解此问题,可以使用 2Captcha 提供的 100% 识别服务,原理是通过将验证码发送给多个员工进行匹配,满足配置的条件才返回结果(根据官方回复,100% 识别服务只能针对 normal captchas 完全生效,对滑块类型的验证基本不可能得到相同的结果相关链接

参考链接|Bibliography

2Captcha 在线破解验证码

脚注

Memory

内存管理相关的系统关键进程

Name Path Info Demonstrate
[kswapd0] 由内核启动 Linux 内核中的一个内存管理守护进程,负责内存交换(swap).当系统内存不足时,触发内存回收机制,释放不常用的内存页。
内存回收使用 Page Replacement 算法(新版本使用)
kswapd
阅读全文 »

内存相关的 system call

system call function 说明 示例
shm open 使用 Shared Memory 方式的 IPC 进程使用此方法创建 shared memory,要相互通信的进程链接到此 FD(File Descripter) fd = shm open(name, O CREAT &#124; O RDWR, 0666);