为避免Docker容器打满磁盘IO,有时需要对容器进行磁盘IO限速。
参考文档:
1 | docker run --name test -d \ |
上面的命令中,限制了容器读写 /dev/sda 的速度:
注意1:device对应的宿主机的磁盘设备,例如 /dev/sda、/dev/sdb1
注意2:创建容器之后,无法通过 update 修改容器磁盘IO限制
注意3:宿主机内核版本在3.13以上才支持blkio cgroups;Docker存储驱动也需要支持blkio cgroups,比如overlay2
1 | version: '3.2' |
1 | docker inspect -f '{{.HostConfig.BlkioDeviceReadBps}}' <container id> |
Adguard Home: Free and open source, powerful network-wide ads & trackers blocking DNS server.
AdGuard Home 是一款免费开源的用于拦截广告和跟踪的DNS服务器,是 AdGuard DNS 的开源版本。
参考文档:
1、下载 adguardhome 镜像
1 | docker pull adguard/adguardhome:v0.107.44 |
2、运行 adguardhome 容器
1 | docker run --name adguardhome\ |
端口说明:
-p 53:53/tcp -p 53:53/udp
: plain DNS.-p 67:67/udp -p 68:68/tcp -p 68:68/udp
: add if you intend to use AdGuard Home as a DHCP server.-p 80:80/tcp -p 443:443/tcp -p 443:443/udp -p 3000:3000/tcp
: add if you are going to use AdGuard Home’s admin panel as well as run AdGuard Home as an HTTPS/DNS-over-HTTPS server.-p 853:853/tcp
: add if you are going to run AdGuard Home as a DNS-over-TLS server.-p 784:784/udp -p 853:853/udp -p 8853:8853/udp
: add if you are going to run AdGuard Home as a DNS-over-QUIC server. You may only leave one or two of these.-p 5443:5443/tcp -p 5443:5443/udp
: add if you are going to run AdGuard Home as a DNSCrypt server.简化版命令:
1 | docker run --name adguardhome\ |
3、查看运行状态
1 | docker ps | grep adguardhome |
1、访问网页配置界面
假设宿主机IP为 192.168.56.101 ,那么 网页配置界面 为:http://192.168.56.101:3000/
2、初始化配置
第一次登录时,AdGuard Home会引导我们对 网页管理界面 进行初始化配置。
初始化配置完成之后,网页配置界面就不能访问了。
配置数据会保存到 /opt/adguardhome/confdir/AdGuardHome.yaml
文件中。
3、访问网页管理界面
假设宿主机IP为 192.168.56.101 ,那么 网页管理界面 为:http://192.168.56.101:80/
点击设置,点击DNS设置,按需配置DNS。
常用配置:
配置数据会保存到 /opt/adguardhome/confdir/AdGuardHome.yaml
文件中。
点击过滤器,点击DNS黑名单。
DNS黑名单,可以阻止访问特定域名。
默认黑名单列表为AdGuard DNS filter,可选的黑名单列表还有几十个。
点击过滤器,点击DNS重写。
DNS重写,可以配置自定义域名解析。
点击过滤器,点击自定义过滤规则。
自定义过滤规则,可以配置自定义域名解析,也可以阻止访问特定域名。
假设宿主机IP为 192.168.56.101 ,那么 resolv.conf 配置为:
1 | nameserver 192.168.56.101 |
具体操作方法参考文档:《DNS入门篇》
]]>当我们定义 Pod 时,可以选择性地为每个容器设定所需要的资源数量。最常见的可设定资源是 CPU 和内存(RAM)大小;此外还有其他类型的资源。
当我们为 Pod 中的 Container 指定了资源 request(请求) 时, kube-scheduler 就利用该信息决定将 Pod 调度到哪个节点上。
当我们为 Container 指定了资源 limit(限制) 时,kubelet 就可以确保运行的容器不会使用超出所设限制的资源。
kubelet 还会为容器预留所 request(请求) 数量的系统资源,供其使用。
参考文档:
CPU 资源的限制和请求以 cpu 为单位。
在 Kubernetes 中,一个 CPU 等于 1 个物理 CPU 核 或者 1 个虚拟核, 取决于节点是一台物理主机还是运行在某物理主机上的虚拟机。
我们也可以表达带小数 CPU 的请求。 当我们定义一个容器,将其 spec.containers[].resources.requests.cpu
设置为 0.5 时, 我们所请求的 CPU 是我们请求 1.0 CPU 时的一半。 对于 CPU 资源单位,数量 表达式 0.1 等价于表达式 100m,可以看作 100 millicpu
。 有些人说成是一百毫核
,其实说的是同样的事情。
CPU 资源总是设置为资源的绝对数量而非相对数量值。 例如,无论容器运行在单核、双核或者 48-核的机器上,500m CPU 表示的是大约相同的计算能力。
memory 的限制和请求以字节为单位。
我们可以使用普通的整数,或者带有以下 数量后缀 的定点数字来表示内存:E、P、T、G、M、k。
我们也可以使用对应的 2 的幂数:Ei、Pi、Ti、Gi、Mi、Ki。
例如,以下表达式所代表的是大致相同的值:
1 | 128974848、129e6、129M、128974848000m、123Mi |
请注意后缀的大小写。如果我们请求 400m 临时存储,实际上所请求的是 0.4 字节。 如果有人这样设定资源请求或限制,可能他的实际想法是申请 400Mi 字节(400Mi) 或者 400M 字节。
ephemeral-storage 本地临时性存储的单位和内存资源的单位相同。
本地临时性存储说明:
节点可以具有本地的临时性存储,由本地挂接的可写入设备或者有时也用 RAM 来提供支持。
临时(Ephemeral)意味着对所存储的数据不提供长期可用性的保证。
Pods 通常可以使用临时性本地存储来实现缓冲区、保存日志等功能。 kubelet 可以为使用本地临时存储的 Pods 提供这种存储空间,允许后者使用 emptyDir 类型的卷将其挂载到容器中。
kubelet 也使用此类存储来保存节点层面的容器日志、 容器镜像文件以及运行中容器的可写入层。
详情参考文档本地临时存储
K8S中,在调度使用GPU资源时,使用不同的 Kubernets Device Plugin,GPU单位也是不同的。
参考文档:
1 |
|
上面的 Pod 有两个容器。每个容器的请求为 0.25 CPU 和 64MiB(226 字节)内存, 每个容器的资源限制为 0.5 CPU 和 128MiB 内存。 我们可以认为该 Pod 的资源请求为 0.5 CPU 和 128 MiB 内存,资源限制为 1 CPU 和 256MiB 内存。
可使用 LimitRange 来设置 namespace 的 request 与 limit 默认值,也可设定 request 与 limit 的最大值与最小值。示例如下:
1 | apiVersion: v1 |
Request 的值并不代表给容器实际分配的资源大小,而是用于提供给调度器。调度器会检测每个节点可用于分配的资源(节点可分配资源 = 节点资源总额 - 已调度到节点上的 Pod 内容器 request 之和),同时记录每个节点已经被分配的资源(节点上所有 Pod 中定义的容器 request 之和)。如发现节点剩余的可分配资源已小于当前需被调度的 Pod 的 request,则该 Pod 就不会被调度到此节点。反之,则会被调度到此节点。
如果不配置 request,调度器就无法感知节点资源使用情况,无法做出合理的调度决策,可能会造成调度不合理,引起节点状态混乱。建议给所有容器设置 request,使调度器可感知节点资源情况,以便做出合理的调度决策。集群的节点资源能够被合理的分配使用,避免因资源分配不均而导致发生故障。
在Kubernetes中,request和limit之间的差异决定了容器的QoS类别。
request == limit
,则容器属于Guaranteed QoS类别。request < limit
,则容器属于Burstable QoS类别。不同的QoS类别有不同的调度和驱逐策略。
节点资源不足时,会触发自动驱逐和删除,优先删除BestEffort容器,其次是Burstable容器,最后是Guaranteed容器。
同时,request和limit之间的差值越大,Burstable类型的容器被驱逐的风险就越高。
对于生产环境中关键的服务,推荐设置 request == limit
,即Guaranteed QoS类别,以保证在节点故障时关键服务不易被驱逐导致线上业务受到影响。
如果应用设置了较高的 request 值,而实际占用资源远小于设定值,会导致节点整体的资源利用率较低。除对时延非常敏感的业务外,敏感的业务本身并不期望节点利用率过高,影响网络包收发速度。
建议对非核心,并且资源非长期占用的应用,适当减少 request 以提高资源利用率。如果我们的服务支持水平扩容,那么除 CPU 密集型应用外,单副本的 request 值通常可设置为不大于1核。例如,coredns 设置为0.1核,即100m即可。
如果我们的服务使用单副本或少量副本,且 request 及 limit 的值设置过大,使服务可分配到足够多的资源去支撑业务。那么某个副本发生故障时,可能会给业务带来较大影响。
当 Pod 所在节点发生故障时,由于 request 值过大,且集群内资源分配的较为碎片化,其余节点无足够可分配资源满足该 Pod 的 request,那么该 Pod 无法实现漂移,无法自愈,会加重对业务的影响。
建议尽量减小 request 及 limit,通过增加副本的方式对我们的服务支撑能力进行水平扩容,使系统更加灵活可靠。
若生产集群有用于测试的 namespace,如不加以限制,则可能导致集群负载过高,影响生产业务。可以使用 ResourceQuota 限制测试 namespace 的 request 与 limit 的总大小。示例如下:
1 | apiVersion: v1 |
在Linux系统中,为了增强安全性,避免不适当的使用,有时需要限制特定用户或用户组的命令行访问。
常用的限制方法包括 profile限制、authorized_keys限制、rbash限制,本文我们就来学习一下这些方法。
参考文档:
当一个shell登录时,它将读取 /etc/profile
文件中的全部环境变量,然后再执行 /etc/profile.d/
目录中的所有 .sh
结尾的脚本。
因此,我们可以定义一个 /etc/profile.d/login.sh
脚本,用来限制用户的PATH,以此限制用户命令。
下面是一个 login.sh 示例,限制用户只能使用 ssh 命令。
1 |
|
但是,这种方法只能限制用户登录后的命令,如果用户远程执行命令,就限制不住了。
比如:
1 | ssh -t work@192.168.55.100 "bash" |
更多关于登录session和非登录session的内容,可以参考《bash_profile和bashrc的区别》
想要限制非登录session,一种可选的方案是使用 authorized_keys 。
1、authorized_keys 中配置 public key
1 | command="/usr/bin/ssh $SSH_ORIGINAL_COMMAND@tiger.voidking.com -p 2222" ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC9... |
2、用户使用ssh
1 | ssh -t work@192.168.55.100 "haojin" |
详情参考:《shell命令之ssh》
rbash(restricted bash)是 bash 的一个版本,实际上 rbash 是 bash 的一个软连接,能够限制用户的命令。
具体限制包括:
/
字符的程序。例如,我们无法执行 /usr/bin/uname 或 ./uname 命令或程序。但是,我们依然可以运行 uname 命令。也就是说,当前目录以外的程序或命令是无法被执行的。>
和 >>
等重定向运算符进行重定向输出。1、创建一个用户
1 | # ls -s /bin/bash /bin/rbash |
2、限制用户只能执行ssh
1 | echo "export PATH=/home/ruser/bin" >> /home/ruser/.bash_profile |
但是,rbash有很多逃逸方法,比如一个简单的bash
命令就可以逃逸,无论是session登录还是非session登录。
1 | ssh -t work@192.168.55.100 "bash" |
外网可以访问的主机A放通一个ssh命令用于登录,主机A可以连通到jumpserver主机。
1、准备一个限制登录脚本 ssh.sh
1 |
|
1 | chmod a+x ssh.sh |
2、定义 Dockerfile
1 | # Using debian as base |
3、打包镜像
1 | docker build -t voidking/ssh:debian-bookworm-slim . |
4、运行镜像
1 | docker run -d --name ssh \ |
配置外部用户的 public key 到ssh容器中 work用户的authorized_keys,以使得外部用户有权限执行 command 中指定的 ssh.sh 脚本。
1 | docker exec -it ssh /bin/bash |
1 | ssh -t work@192.168.55.100 -p 10022 "haojin" |
本文中,我们学习在GitHub Actions中实现PyPI发版。
具体来说,就是在GitHub Actions中实现打包Python软件包,并且上传软件包到 pypi.org 站点。
相关文档:
GitHub 项目仓库中,添加一个名为 PYPI_API_TOKEN
的 secret ,它的值是从 pypi.org 获取到的API TOKEN。
这个secret,使得 workflow 有权限向 pypi.org 上传Python软件包。
新建一个workflow,例如 .github/workflows/build-package.yaml
内容为:
1 | name: Build and upload python package |
1、打tag
1 | git tag v0.6.4 |
2、github发版
github项目页面,点击左侧的 Releases
,点击Draft a new release
选择tag,Release title
输入版本号 v0.6.4
,点击 Publish release
3、pypi自动发版
github发版后,会触发 workflow ,自动打包并发版到 pypi.org
Mermaid: JavaScript based diagramming and charting tool that renders Markdown-inspired text definitions to create and modify diagrams dynamically.
参考文档:Mermaid
1、安装nvm
nvm安装方法参考文档《MacOS上软件配置》
2、安装v20版本node
1 | nvm install v20.10.0 |
node版本要大于v14,更低版本的node会报错 SyntaxError ,详情参考 Client does not start
3、使用v20版本node
1 | nvm use v20.10.0 |
1 | export PUPPETEER_SKIP_DOWNLOAD="true" |
1、下载chromium
2、放置chromium到指定路径
1 | unzip chrome-mac.zip |
mmdc是Mermaid CLI(命令行接口)的核心命令,用于把Mermaid图表代码转换为图像文件(如SVG、PNG、PDF)。
mmdc语法:
1 | mmdc -i input -o output |
参数说明:
1、创建 pupeteer 配置文件 puppeteer-config.json
1 | { |
如果使用Chrome的话,配置内容如下
1 | { |
2、创建一个 mmd 文件 flowchart.mmd
1 | graph TD; |
3、生成图表
1 | mmdc -i flowchart.mmd -o flowchart.png -p puppeteer-config.json |
The pytest framework makes it easy to write small, readable tests, and can scale to support complex functional testing for applications and libraries.
pytest是一种卓越的Python测试框架,它提供了简单、高效的方式来编写可以扩展的测试用例。
本文学习pytest的测试用例写法,内容整理自 chatgpt gpt-4-0613 。
相关文档:
准备一个mathlib模块,包含一个求和函数add():
1 | # mathlib.py |
Python中编写测试用例,一种常见的方式是创建一个以test_
为前缀的函数,这个函数应包含测试用例的名字和内部执行逻辑。
我们想要创建一个测试用例来检验 add 函数,我们可以创建一个 test_mathlib.py 文件:
1 | # test_mathlib.py |
1 | pytest test_mathlib.py |
为了使测试更丰富,我们可以使用 @pytest.mark.parametrize
装饰器为函数参数提供多组值:
1 | # test_mathlib.py |
Fixture(预置) 是 pytest 提供的一种特殊的函数,它将测试前的准备工作和解除步骤打包成一个函数,以供测试用例调用。这样做可以提高测试的可重用性和代码的可读性。
例如,我们要为数据库相关的测试都创建一个测试数据库,并在测试结束后清理掉,可以写个fixture如下:
1 |
|
然后在测试函数中使用这个 db fixture:
1 | def test_database(db): |
Mocking(模拟) 是一种强大的技术,它可以模拟我们在测试中所依赖的部分的行为。例如,我们的函数可能依赖于一个第三方服务或者数据库,在测试环境中,很可能无法启动这些服务。这时,就可以用 Mock 对象替代这些服务或者数据库。pytest 提供了 unittest.mock 作为内置的 mocking 框架。
下面是一个简单的 mocking 例子,假设我们有一个打印函数 print_content()
,我们并不希望在测试的时候真的打印出来:
1 | from unittest.mock import MagicMock |
在 pytest 中,Marker(标记)用于给测试用例添加元数据。比如最常见的 skip 和 xfail,它们会让 pytest 跳过或者期望失败的测试用例。
1 | import pytest |
@pytest.mark.asyncio
也是一个常用的内置装饰器,用于标记需要异步执行的函数。
Python3.5 版本引入了 async / await 关键字支持原生协程,它允许我们编写异步的代码,而不需要依赖于特定的包或者复杂的回调链。然而,pytest 是同步的,它不能原生支持 async / await 式的测试。这就是 pytest.mark.asyncio 装饰器的作用: 它让我们能够以同步的方式来测试异步的代码。
我们也可以自定义 marker。然后我们可以在运行 pytest 的时候指定参数 -m
来只运行有特定标记的测试用例,从而帮助我们更好地管理和运行我们的测试。
1 |
|
Git LFS: An open source Git extension for versioning large files
Git Large File Storage (LFS) replaces large files such as audio samples, videos, datasets, and graphics with text pointers inside Git, while storing the file contents on a remote server like GitHub.com or GitHub Enterprise.
Git LFS (Large File Storage)是一个开源的Git大文件版本控制的解决方案和工具集,工具自身是基于Golang进行实现,并在Github上开源。原理上是通过对Git客户端进行扩展的方式,从而集成并兼容了原生的Git客户端。Git LFS良好的设计,让用户感觉在对大文件处理过程中,与普通Git的使用方式上没有任何差别,也就是说,在使用方式上Git LFS对用户是完全透明的。
参考文档:
1、下载适合系统的 git-lfs/releases
2、解压安装
解压后,执行 install.sh
脚本,这个脚本会做两个事情:
$PATH
中安装Git LFS的二进制可执行文件git lfs install
命令,让当前环境支持全局的LFS配置安装成功,会输出:
1 | Git LFS initialized. |
参考文档:Git LFS - Installation instructions
Linux Debian:
1 | curl -s http://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | sudo bash |
RPM packages:
1 | curl -s http://packagecloud.io/install/repositories/github/git-lfs/script.rpm.sh | sudo bash |
1 | brew install git-lfs |
目前lfs已经集成在了Git for Windows 中,直接下载和使用最新版本的Windows Git即可。
1 | git lfs install |
如果官方脚本安装,那么不需要执行这条命令。
1、设置LFS追踪 mp4 类型的文件
1 | git lfs track "*.mp4" |
track 命令实际上是修改了仓库中的 .gitattributes
文件。
2、查看LFS追踪的文件类型
1 | git lfs track |
3、提交 .gitattributes
文件
1 | git add .gitattributes |
4、放入一个 mp4 类型的文件到仓库中
5、提交并推送 mp4 类型文件
1 | git add test.mp4 |
推送后,查看该mp4文件,会显示 Stored with Git LFS 。
注意:github中fork的仓库是不支持LFS上传大文件的,详情参考:can not upload new objects to public fork。如果想要上传大文件,需要源仓库管理员授权push的权限。
]]>Git 提供了一种称为钩子(hook)的特性,帮助我们在关键时刻自动执行自定义脚本。
其中,名为 pre-commit
的钩子会在每次 commit 之前运行,能够作为保障代码质量的工具。
在项目的根目录下,找到 .git/hooks
文件夹,这个文件夹中存放的就是各种钩子脚本。
创建一个新文件命名为 pre-commit ,务必不要添加后缀,如 .sh 或 .py。
在 pre-commit 文件中,我们可以添加任何可以执行的脚本。
例如,如果我们针对 Python 的 .py 文件进行检查,则我们可能的 pre-commit 内容如下:
1 | #!/usr/bin/env bash |
这个检查脚本的意思是,如果我们的 .py 文件中含有 pdb.set_trace(),那么拒绝该次 commit。
设置完后,我们需要使脚本具有执行权限,使用 chmod +x .git/hooks/pre-commit
命令即可。
之后,每一次的 git commit,在提交之前,都会执行我们定义好的 pre-commit 脚本,保证代码符合我们设置的规范,从而提升代码质量。
当我们有大量项目时,pre-commit 脚本的管理维护就变成了一件痛苦的事情。
此时,就需要 pre-commit 框架出马了。pre-commit 框架是一个支持多语言的 pre-commit 脚本的管理器,能够简化我们的 pre-commit 脚本配置。
使用 pre-commit 框架时,在 .pre-commit-config.yaml
配置文件指定所需的linter列表(脚本列表),然后 pre-commit 框架会自动下载这些linter并运行。
需要特别说明的是:一些最好的 linter 可能是项目中不使用的语言编写的。例如 scss-lint 是一个用于检查SCSS的 linter,但是它是用Ruby编写的。而我们使用 pre-commit 框架时,完全不用关心 scss-lint 的安装配置,只要在linter列表中指定使用它即可。
参考文档:
1 | pip install pre-commit |
1、创建 pre-commit 框架配置文件 .pre-commit-config.yaml
1 | default_stages: [ commit ] |
2、运行pre-commit框架
1 | pre-commit run --all-files |
3、配置commit前自动调用pre-commit框架
1 | cat <<EOF > .git/hooks/pre-commit |
4、测试commit
1 | # modify something |
github actions 中,也可以配置使用 pre-commit 框架,用于检查代码规范。
项目根目录中,新建 .github/workflows/pre-commit.yaml
,内容为:
1 | name: Pre-commit checks |
提交到github,就OK了。
Git钩子是一些在Git执行特定操作时触发的脚本,可以用于自定义和自动化工作流程,不同的Git钩子有不同的调用时间。
客户端钩子:
服务器端钩子:
每个项目的.git/hooks
的目录中,看到这些钩子的官方示例。
示例文件以.sample
结尾,去掉.sample
后缀可激活该钩子脚本。
参考文档:
]]>Gitlab CI中可以配置代码质量检查,同样的,GitHub Actions中也可以配置代码质量检查。
本文中,我们学习在GitHub Actions中配置Python的编码规范检查和运行单元测试。
参考文档:
详情参考 《git pre-commit 代码质量检查》。
使用多个Python版本运行单元测试。
1 | name: Python application test |
1 | name: Python application test |
1、安装单测依赖
1 | pip install pytest pytest-cov coverage-badge |
2、生成单测覆盖率结果文件 .coverage
和 html 格式报告
1 | pytest tests/ --doctest-modules --cov=. --cov-report=html |
pytest参数说明:
tests/
指定测试文件的路径--doctest-modules
运行所有发现的doctest模块--junitxml=junit/test-results.xml
指定生成junitxml格式的测试报告--cov=.
生成单测覆盖率结果文件 .coverage
必须的参数,指定要收集哪些代码的覆盖率信息,.
表示收集当前目录下所有代码的覆盖率信息--cov-report=html
指定生成 html 格式的测试覆盖率报告,存到 htmlcov 目录中,等同于单独运行 coverage html -i
--cov-report=xml
指定生成 xml 格式的测试覆盖率报告,存储为 coverage.xml ,等同于单独运行 coverage xml -i
3、查看测试覆盖率
1 | coverage report -m |
4、生成badge svg
1 | coverage-badge -o coverage.svg |
5、github README 引用 badge
1 | ![Coverage Status](/path/to/coverage.svg) |
或者:
1 | [![Coverage Status](/path/to/coverage.svg)](https://your-badge-link) |
1、github actions配置
1 | name: Python application test |
2、github README 引用 badge
1 | ![Coverage Status](https://object-storage-domain/path/to/coverage.svg) |
项目更目录中,创建 coverage 配置文件 .coveragerc
1 | [run] |
omit 用于指定不应该包含在覆盖率统计中的文件或目录,exclude_lines 用于指定不应该包含在覆盖率统计中的代码行。
1 | jobs: |
用户提交PR后,想要触发审批,配置是很简单的,例如:
1 | on: |
但是,如果我们在workflow中用到了secret,那配置就没有这么简单了。
因为github限制了pull_request
触发的workflow读取secret的权限,所以副本仓库提交到主仓库的pr,读取不到主仓库secret。
这是一种对主仓库secret的保护,详情参考文档github actions main repository secret not picked up from pull request build
如果确实需要让pr的workflow读取到secret,该怎么处理?Keeping your GitHub Actions and workflows secure Part 1: Preventing pwn requests 这篇文章提供了两种方法可供参考。
方法一:pr事件触发workflow1,workflow1结束事件触发workflow2,此时workflow2就有权限读取secret了。但是,这种方法中,workflow1和workflow2之间缺少直观的关联,在pr页面和github actions页面上都看不出来联系,不友好。
方法二:使用 pull_request_target
代替 pull_request
,此时触发的workflow有权限读取secret。配置简单,页面也能直观看到,但是,这种方法降低了安全性。
方法一和方法二各有优劣,个人更推荐方法二,因为方法二可以配合environment
加一道审批,增强安全性,弥补缺陷。
此外,使用 pull_request_target
时, actions/checkout@v4
默认切分支是切到 target 分支,想要测试pr分支,需要指定切分支到pr head。详情参考Checkout V4
1 | on: |
pull_request
和 pull_request_target
是有很大区别的,Events that trigger workflows - pull_request_target 文档中说:
This event runs in the context of the base of the pull request, rather than in the context of the merge commit, as the pull_request event does.
个人理解为:pull_request
的workflow是根据pr合并后的workflow yaml运行,而pull_request_target
的workflow是根据pr合并前的workflow yaml运行的,详情参考文档:What is the difference between pull_request and pull_request_target event in GitHubActions
注意:如果一个pr中修改了 workflow ,那么在github actions页面看到的 workflow yaml 就是修改后的。但是如果是pull_request_target
事件触发的workflow,那么虽然看到了修改后的yaml,实际执行会按照修改前的yaml执行。
青龙面板是一个支持 Python3、JavaScript、Shell、Typescript 的定时任务管理平台
Linux自带的crontab可以配置定时任务,但是并不方便。而使用青龙面板,能够可视化配置定时任务,简单快捷。
本文中,我们学习一下青龙面板的安装配置,试一试签到薅羊毛。
参考文档:
1、下载青龙面板Docker镜像
1 | docker pull whyour/qinglong:debian |
2、启动青龙面板
1 | docker run --name qinglong -d \ |
以上命令:
3、验证安装
1 | docker ps |
4、登录进容器
1 | docker exec -it qinglong /bin/bash |
5、web访问青龙面板
浏览器访问 http:<ip>:5700
初次访问时,会提示进行初始化配置。
1 | # 依次执行,如果设置了随机延迟,将随机延迟一定秒数 |
1 | # 更新并重启青龙 |
参数说明:
点击左侧配置文件,找到 RepoFileExtensions="js py"
,修改为 RepoFileExtensions="js py sh ts"
,右上角保存。
点击左侧对比工具,对比修改前后的变化。
点击左侧依赖管理,创建依赖,名称一栏中输入脚本可能需要的依赖,多个依赖换行输入,点击确定即可下载安装依赖。
点击左侧通知设置,选择一个通知方式,根据提示填入必要的信息,保存。
建议使用飞书机器人,配置最简单:飞书群里新建一个自定义机器人,把webhook地址的最后一段粘贴到larkKey即可。
青龙面板设置里的那个只是用来面板级别的通知,比如订阅更新。而脚本里的通知,需要在配置文件里去配置的。详情参考文档如何设置任务执行完毕后发送通知
1、微信登录 Server酱,获取一个SendKey,测试通知
2、点击左侧配置文件,找到 PUSH_KEY
,填入上一步获取到的 SendKey,保存
点击左侧环境变量,添加两个关于代理的环境变量。
1 | http_proxy=http://192.168.5.233:20171 |
之所以要配置代理,是因为很多订阅是从github拉取的,而github从国内访问是需要科学上网的,因此最好配置一下代理。
这两个代理变量,平时禁用,拉取订阅时启用。
参考文档:github - mrabit/aliyundriveDailyCheck
1、获取阿里云盘 refresh_token
web登录阿里云盘后,控制台粘贴
1 | copy(JSON.parse(localStorage.token).refresh_token); console.log(JSON.parse(localStorage.token).refresh_token); |
2、青龙面板添加环境变量 refreshToken
如果有多个账号要签到,那就添加多个refreshToken。
3、安装js依赖
1 | axios |
4、添加订阅
1 | ql repo https://github.com/mrabit/aliyundriveDailyCheck.git "autoSignin" "" "qlApi" |
添加订阅后,点击运行,即可从github拉取定时任务。拉取成功之后,建议禁用订阅。
5、配置定时任务
点击定时任务页面,找到 autoSignin.js 任务,点击运行,测试运行。
测试没有问题,编辑定时任务,设置一个合适的运行时间。
6、配置自动更新 refreshToken
系统设置,应用设置,创建一个应用 autoSignin(名称随意)。
autoSignin 应用的 CLIENT_ID 和 CLIENT_SECRET 配置到环境变量中。
最近买了个85寸电视,就想搞个NAS。
看了看价格,绿联NAS DX4600 2000左右,蜗牛星际NAS 1000左右,硬盘还需要另外购买。贫穷,让我想到了废弃已久的华为荣耀笔记本电脑。
要不然,用它作为NAS?还可以作为软路由?还可以部署Nginx、Jupyter、ChatGPT代理等常用服务,还可以参考 Awesome-Selfhosted 部署更多有趣的项目,想想还挺不错。搞起来!
NAS,全称为网络附属存储(Network Attached Storage),是一种专门的网络存储设备。NAS 设备通过网络直接连接到其他设备,用户可以随时随地通过网络存取NAS中的数据。
NAS设备的主要功能是提供数据存储和备份,同时还可能有流媒体服务、打印服务等其他功能。NAS设备可用于家庭和企业,帮助实现数据共享和存储管理,特别在企业场景下,NAS可以优化数据备份、共享和远程访问等业务流程。
软路由是指使用普通计算机和路由软件实现的具有路由功能的设备。与一般的硬件路由器不同,软路由器可以运行在商用操作系统上,并由用户自定义和配置,以满足特定网络环境和应用的需求。软路由可以提供诸如路由转发、防火墙、VPN、流量管理等多种功能。
NAS和软路由一体化设备,就是同时实现网络路由和数据存储功能的设备。它既能提供网络路由和防火墙等网络服务,又能提供文件共享和数据备份等存储服务。以下是几种常见的一体化方案:
参考文档:
参考文档:Create a bootable USB stick on macOS
1、服务器系统选择 ubuntu-18.04.6-desktop-amd64.iso
之所以选择desktop版,是因为desktop版是图形化界面,初始化配置很方便。后期不想要desktop的话,可以卸载掉。
2、使用balenaEtcher制作一个U盘启动盘
3、笔记本插入U盘,开机选择从U盘启动
4、根据提示安装Ubuntu系统
系统分区时注意事项:
New Partition Table
,如果分错了就Revert
重新搞。bios
,格式reserved bios boot areaefi
,格式efi/boot
,格式ext4/
,格式ext4在现代电脑系统(使用UEFI模式)中,电脑首先引导到EFI分区,EFI分区中的UEFI启动加载器,接着加载/boot分区中的操作系统内核,然后操作系统开始运行。
参考文档:
图形界面配置。
或者参考《Ubuntu18配置静态IP》,使用命令行配置。
1、编辑logind配置
1 | vim /etc/systemd/logind.conf |
修改其中的配置为:
1 | HandleLidSwitch=ignore |
HandleLidSwitch是指笔记本屏幕合起来,设置为ignore,也就是笔记本屏幕合起来时不进行任何改变。
2、重启 systemd-logind
1 | systemctl restart systemd-logind |
1、安装Samba
1 | apt install samba |
2、查看Samba服务状态
1 | systemctl status nmbd |
1、创建共享目录并设置权限
1 | mkdir -p /data/samba/video |
用户组sambashare是在安装Samba过程中自动创建的。
3、创建samba用户并授权
1 | useradd -m -s /usr/sbin/nologin -G sambashare samba |
Samba权限控制使用Linux用户和组的权限系统,但具有自己的身份验证机制,与标准Linux身份验证分开。
4、配置共享目录和用户
编辑samba配置文件
1 | vim /etc/samba/smb.conf |
在文件最后添加:
1 | [video] |
配置说明:
[video]
和 [doc]
表示登录时使用的共享名称。path
表示共享的目录。browseable
表示可浏览,是否可在共享列表中列出此共享。如果设置为no,其他用户将看不到共享目录。read only
表示valid users列表中指定的用户是否设置仅允许读,如果值yes,则仅允许读。force create mode
表示此共享创建文件时设置的文件权限模式。force directory mode
表示此共享创建目录时设置目录权限的模式。valid users
表示允许访问共享的用户和组的列表。群组以@
符号为前缀。更多配置选项,请参考文档 smb.conf — The configuration file for the Samba suite
5、重启samba
1 | systemctl restart nmbd |
1、安装 samba client
1 | apt install smbclient |
2、创建测试文件
1 | touch test.txt |
3、连接samba server
1 | smbclient //192.168.5.233/users -U samba |
4、上传下载文件
1 | smb: \> ls |
下载文件时,还可以使用smbget工具
1 | smbget -U samba smb://192.168.5.233/video/test.txt -o test3.txt |
1 | ufw allow 'Samba' |
参考文档:《Docker入门篇》
参考文档dockerhub - messense/aliyundrive-webdav,通过在线工具获取 refresh token。
以前通过浏览器自行获取refresh token的方法已失效,详情参考 Error: Invalid refresh token value found in –refresh-token argument。
1、拉取webdav镜像
1 | docker pull messense/aliyundrive-webdav:2.3.3 |
2、启动webdav容器(本地文件服务器)
1 | docker run -d --name=aliyundrive-webdav \ |
3、查看webdav容器状态
1 | docker ps |
1、安装webdav驱动
1 | apt install -y davfs2 |
2、创建挂载目录
1 | mkdir -p /data/aliyundrive |
3、挂载阿里云盘
1 | mount -t davfs http://192.168.5.233:8080/ /data/aliyundrive |
4、查看挂载
1 | cd /data/aliyundrive |
本地目录挂载阿里云盘后,和其他普通目录一样,也可以通过samba共享给其他主机。
samba配置如下:
1 | [aliyundrive] |
如果担心访问阿里云盘时候的网络不稳定,可以把一部分文件下载到本地磁盘。
1 | screen rsync -P -azv '爱情公寓' /data/samba/video |
下载速度很快,家庭千兆宽带大概平均 10MB/s,峰值 30MB/s。
]]>当CentOS系统崩溃无法正常启动时,往往需要进入救援模式进行恢复。
本文中,我们学习一下CentOS救援模式的使用方法。
参考文档:
通过外接设备(KVM/显示器键盘)或者VNC连接到主机。
1、开机启动,在出现内核选项时按下 e
进入编辑
2、添加内核参数
centos7找到 linux16
开头的行并在行尾添加内核参数 rd.break
centos8找到 linux
开头的行并在行尾添加内核参数 rd.break
3、并按 ctrl+x
进入单用户模式
4、挂载并更改根目录
1 | mount –o remount,rw /sysroot |
通过外接设备(KVM/显示器键盘)或者VNC连接到主机。
1、插入包含CentOS系统的光盘或者U盘
2、开机启动,按下F12,选择从光盘或者U盘启动
3、启动后选择 Troubleshooting,Rescue a CentOS system
如果root密码丢失,主机刚好启动失败,这时候就必须通过救援模式修改root密码了。
1、进入自带救援模式
2、操作修改root密码
1 | passwd root |
1、进入自带救援模式
2、查看系统启动日志,找到具体的启动失败的原因
1 | journalctl -xb |
断电后的启动失败,极大概率是因为挂载问题。
例如,如果提示时因为 /data
目录的挂载问题,那么就在 /etc/fstab
中注释掉 /data
目录的挂载。
然后重启主机即可 reboot
问题原因:rm /boot/grub* -rf
问题表现:启动时出现报错 error: file ‘/grub2/i386-pc/normal.mod’ not found.
1、进入第三方系统救援模式
2、更改根目录
1 | chroot /mnt/sysimage |
问题原因:rm /boot/* -rf
问题表现:启动时出现报错 error: file ‘/grub2/i386-pc/normal.mod’ not found.
1、进入第三方系统救援模式
2、更改根目录
1 | chroot /mnt/sysimage |
救援模式(Rescue Mode):也称作单用户模式,主要用于修复系统问题。在这种模式下,系统会尝试挂载所有的文件系统,启动网络服务,让你有机会对系统进行彻底的维护。你可以更改系统文件,修复系统问题(比如重设root密码,修复GRUB启动器问题等)。这是一个维护和修复系统问题的模式。
紧急模式(Emergency Mode):这是最低级别的启动模式,只会提供最少的系统功能(仅启动根文件系统,这个文件系统默认会以只读方式进行挂载),不会启动网络连接,不会尝试挂载其他文件系统。这种模式主要用于在无法进入 Rescue 模式时进行最低级别的系统问题排查。
]]>网络排查工程常常包含了诊断网络中断和稳定性问题。在这些场合下,网络工程师们通常会使用一些有效的网络工具来帮助他们准确地查找问题所在。其中,MTR是一款极其实用的网络诊断工具。
MTR,全名为My Traceroute,是一款网络诊断工具,结合了traceoute和ping两种常见工具的功能。通过源自源主机到目标主机的网络连接的持续跟踪,MTR能提供每个路由节点的响应速度和系统稳定性情况。
参考文档:
MTR是开源的,我们可以在大多数的Linux发行版中找到它。
在Ubuntu或Debian系统中,我们可以通过下列命令来进行安装:
1 | sudo apt-get install mtr |
如果我们正在使用CentOS或者Fedora,可以使用
1 | sudo yum install mtr |
1 | mtr 192.168.56.101 |
运行后,MTR将运行统计报告,展示当前主机到目标主机的每一跳联网情况。
运行结果的主要信息如下:
在MTR运行时,我们能看到各路由节点的丢包率,如果某一跳的丢包率很高,那么这就可能是网络问题的所在。
大多数情况,只需要关注最后一跳(目的地址)是否有丢包即可。
此外,MTR并不仅仅提供实时的网络连接状态,还可以通过生成报告的方式保存网络状态。
通过在命令后添加”–report”,MTR将在运行一定时间后生成一个报告。
1 | mtr --report 192.168.56.101 |
本文学习并实践CentOS7内核升级方法,备忘。
参考文档:
1 | cat /etc/redhat-release |
1、导入public key
1 | yum -y update |
2、安装ELRepo仓库的yum源
1 | yum install -y https://www.elrepo.org/elrepo-release-7.el7.elrepo.noarch.rpm |
3、查看可用内核包
1 | yum --disablerepo="*" --enablerepo="elrepo-kernel" list available |
输出内容示例:
1 | Available Packages |
长期维护版本为 kernal-lt ,最新主线稳定版为 kernal-ml ,这里选择 kernal-lt
1、安装新版内核 kernal-lt
1 | yum --enablerepo=elrepo-kernel install -y kernel-lt |
安装成功会输出:
1 | Running transaction |
2、查看可用内核版本及启动顺序
1 | awk -F\' '$1=="menuentry " {print i++ " : " $2}' /boot/grub2/grub.cfg |
输出内容示例:
1 | 0 : CentOS Linux 7 Rescue 05110432cb69b45d6c089de56b266fed (5.4.258-1.el7.elrepo.x86_64) |
1、安装内核升级辅助工具 grub2-pc
1 | yum install -y grub2-pc |
2、设置默认内核
1 | grub2-set-default 1 |
3、生成 grub 配置文件,重新创建内核配置
1 | grub2-mkconfig -o /boot/grub2/grub.cfg |
4、再次查看可用内核版本及启动顺序
1 | awk -F\' '$1=="menuentry " {print i++ " : " $2}' /boot/grub2/grub.cfg |
此时,CentOS Linux (5.4.256-1.el7.elrepo.x86_64) 7 (Core)
的排序号会变成0。
5、修改grub配置
1 | vim /etc/default/grub |
修改 GRUB_DEFAULT
的值为 0
(默认为saved
),其他参数不用变。
1、重启系统
1 | reboot |
2、查看当前内核版本
1 | uname -r |
以上,内核升级完成。
1、查看可用内核列表
1 | rpm -qa | grep kernel |
输出示例:
1 | kernel-tools-libs-4.19.188-10.el7.ucloud.x86_64 |
2、删除旧内核
1 | yum remove -y kernel-4.19.188 kernel-devel-4.19.188 kernel-headers-4.19.188 |
3、删除旧版本工具包
1 | yum remove kernel-tools-libs-devel-4.19.188-10 kernel-tools-4.19.188-10 |
PS:安装yum-utils 工具,当系统安装的内核大于3个时,会自动删除旧的内核版本
1 | yum install -y yum-utils |
1、安装新版本工具包
1 | yum --disablerepo=\* --enablerepo=elrepo-kernel install -y kernel-lt-tools.x86_64 |
2、查看已安装内核和工具包
1 | rpm -qa | grep kernel |
《Hexo本地搜索加速》一文中,给 search.xml 文件配置了 jsdelivr CDN。但是,jsdelivr CDN 目前国内已经无法访问了,只能另外寻找一个替代。
可选的替代包括:
配置方法可以参考hexo-theme-next/commit/2ff6c11,但是,这些替代CDN,国内也无法访问。找来找去,最终锁定了七牛,一直用它作为图床,其实用做 search.xml 文件的存储仓库,也很合适。
本文就来学习一下使用七牛作为 search.xml 存储仓库的方法。
参考文档《Hexo环境搭建2021年8月版》,安装配置hexo环境。
执行 hexo g
命令,在 public 目录中生成要部署的静态文件,其中包含 search.xml 。
访问七牛密钥管理页面,创建一个密钥对(AccessKey/SecretKey)。
1 | npm install qiniu --save |
参考文档:对象存储 - Node.js SDK
1、实现上传脚本 upload-qiniu.js
1 | const qiniu = require('qiniu'); |
2、测试上传脚本
1 | node upload-qiniu.js |
上传成功后出现提示:
1 | 上传成功 { hash: 'FkYxkyrsSytBGvgYgEvPs28lVI40', key: 'doc/search.xml' } |
Next主题中,配置使用七牛CDN中的 search.xml。
具体配置方法参考hexo-theme-next/commit/2ff6c11
参考《Hexo配置GitHub Actions自动构建发布》,配置自动部署。
具体配置方法参考hexo-deploy/commit/0e3503d。
在现代软件开发中,Docker 已经成为一项极为重要的技术,而 Makefile 则是构建和自动化流程的有力工具。将 Docker 和 Makefile 结合起来,可以显著简化应用程序的构建、测试和部署流程,提高开发效率和可维护性。
Docker 是一种容器化技术,允许开发者将应用程序及其依赖项打包成一个独立的容器。这个容器包含了运行应用所需的所有组件,包括操作系统、库、环境变量等。这使得应用在不同的环境中能够一致地运行,避免了“在我的机器上能运行”的问题。
Docker 的主要概念包括镜像(Image)和容器(Container):
镜像:一个镜像是一个只读的模板,包含了运行应用所需的文件系统、代码和配置。镜像是构建容器的基础。
容器:容器是基于镜像创建的一个运行实例,它隔离了应用及其依赖项,使得应用可以在一个隔离的环境中运行。
Makefile 是一个文本文件,其中定义了一系列规则,用于自动化构建过程。通过 Makefile,开发者可以定义源代码的依赖关系,以及如何编译、链接和构建最终的应用程序。
Makefile 的基本结构如下:
1 | target: prerequisites |
以下是一个简单的示例 Makefile,用于编译一个包含两个源文件的 C 程序:
1 | CC = gcc |
在这个示例中,有三个目标:
通过在命令行中运行 make 命令,Make 工具会查找当前目录下的 Makefile 文件,并根据定义的规则执行构建操作。例如,运行 make 将会编译源文件并生成可执行文件。
.PHONY
是一个特殊的目标,用于声明一组伪目标(Phony Targets)。伪目标是那些并不代表真实文件的目标,而是代表一些操作或动作。使用 .PHONY 可以告诉 Make 工具,这些目标不应该被当作文件名进行比较,而是始终会执行对应的命令,无论文件是否已经存在。
带有 .PHONY
的示例 Makefile:
1 | .PHONY: clean build run |
在这个示例中,.PHONY
声明了三个伪目标:clean, build, 和 run。当你运行 make clean
,make build
,或 make run
时,Make 工具将会执行与这些目标关联的命令,而不会考虑文件名的存在与否。
Makefile 可以更加复杂,支持条件语句、循环、变量等功能,使其能够适应各种项目的构建需求。使用 Makefile 可以提高开发效率,确保代码在不同环境下能够正确地构建。
参考项目:github - voidking/python-wechaty-template
项目中Makefile内容为:
1 | P=$(shell pwd) |
项目中Dockerfile内容为:
1 | FROM python:3.9 |
宿主机上执行 make bot
,调用流程如下:
1、从Makefile中找到目标bot对应的命令,执行
1 | make build |
2、从Makefile中找到build和dockerrun对应的命令,执行
1 | docker build -t py-wechaty-template-bot:latest . |
3、执行docker build
时,当前目录中的Makefile和其他文件一起被拷贝到了容器中
4、执行docker build
中的make install
时,从Makefile中找到install对应的命令,容器中执行
1 | pip install -r requirements.txt |
5、执行docker build
结束时,指定镜像的启动命令为make run
,从Makefile中找到run对应的命令为python bot.py
6、执行docker run
时,因为没有指定启动命令,所以执行默认启动命令
1 | python bot.py |
将 Docker 和 Makefile 结合,为开发者带来了许多优势:
综上所述,结合 Docker 和 Makefile 可以使得容器化应用的构建和部署变得更加高效、可靠,并且易于维护。这种结合为现代软件开发提供了一种强大的工具,能够帮助开发者更好地管理复杂的构建流程。
]]>Mermaid是一种用于描述图表的文本语言,它支持多种图表类型,如流程图、序列图、甘特图等。通过简单的文本描述,就可以生成复杂的图表,而不需要手动绘制。
Mermaid可以与Markdown结合使用,方便快捷地在文档中插入图表。本文将介绍如何使用Mermaid语言在Markdown文档中绘制各种类型的图表。
参考文档:
Mermaid通常不需要额外的安装,因为它是在浏览器中渲染的。
想要在Markdown中使用Mermaid语言,需要Markdown编辑器支持Mermaid语法,并启用了Mermaid渲染插件。
在Markdown文档中插入Mermaid图表非常简单。只需使用三个反引号(```)将Mermaid代码块括起来,并在反引号后指定Mermaid语言。
参考文档:
1、安装 hexo-filter-mermaid-diagrams 插件
1 | npm install hexo-filter-mermaid-diagrams --save |
2、Next主题启用Mermaid
1 | # Mermaid tag |
具体修改参考next主题修改commit/0790595d。
流程图是描述流程、决策和步骤的图表。以下是一个简单的流程图示例:
1 | graph LR |
上述代码使用Mermaid语法绘制了一个由三个节点组成的流程图。
graph LR A[开始] --> B[中间步骤] B --> C[结束]
序列图用于展示多个参与者之间的交互过程。以下是一个简单的序列图示例:
1 | sequenceDiagram |
上述代码使用Mermaid语法绘制了Alice和Bob之间的简单交互过程。
sequenceDiagram participant Alice participant Bob Alice ->> Bob: 你好,Bob! Bob -->> Alice: 你好,Alice!
甘特图用于展示任务的时间轴和进度。以下是一个简单的甘特图示例:
1 | gantt |
上述代码使用Mermaid语法绘制了一个包含两个项目的甘特图,每个项目有多个任务。
gantt title 项目计划 dateFormat YYYY-MM-DD section 项目A 任务1 :a1, 2023-08-01, 7d 任务2 :after a1, 3d section 项目B 任务3 :2023-08-10, 5d 任务4 :2023-08-15, 4d
Mermaid支持许多高级用法和样式设置,例如节点样式、连接线样式、图表方向等。更多信息请参考Mermaid官方文档。
通过Mermaid语言,我们可以在Markdown文档中轻松绘制流程图、序列图、甘特图等各种类型的图表。只需按照本教程的指导,使用Mermaid语法编写图表代码,并确保我们的Markdown编辑器支持Mermaid渲染,即可轻松创建复杂的图表内容。
]]>本文学习使用Python调用OpenAI API的方法,基于openai python库 openai==0.27.8
注意:openai python库版本更新很快,本文并不适用更高版本openai python库。
参考文档:
1 | pip install openai==0.27.8 |
1 | usage: openai [-h] [-V] [-v] [-b API_BASE] [-k API_KEY] [-p PROXY [PROXY ...]] [-o ORGANIZATION] {api,tools,wandb} ... |
1 | export OPENAI_API_KEY="sk-xxx" |
1 | # 测试官方OPENAI API |
执行openai命令前,需要先配置KEY,否则会报错:
1 | Error: No API key provided. You can set your API key in code using 'openai.api_key = <API-KEY>', or you can set the environment variable OPENAI_API_KEY=<API-KEY>). If your API key is stored in a file, you can point the openai module at it with 'openai.api_key_path = <PATH>'. You can generate API keys in the OpenAI web interface. See https://platform.openai.com/account/api-keys for details. |
或者,执行openai命令时,使用参数-k
配置KEY。
执行可能会卡住一段时间后报错:
1 | [2023-08-05 08:55:26,852] Retrying (Retry(total=1, connect=None, read=None, redirect=None, status=None)) after connection broken by 'NewConnectionError('<urllib3.connection.HTTPSConnection object at 0x7f94afde5d30>: Failed to establish a new connection: [Errno 110] Connection timed out')': /v1/chat/completions |
也可能会直接报错:
1 | Error: Error communicating with OpenAI: ('Connection aborted.', ConnectionResetError(54, 'Connection reset by peer')) |
解决办法一:配置全局代理(推荐)
1 | export https_proxy=http://127.0.0.1:7890 http_proxy=http://127.0.0.1:7890 all_proxy=socks5://127.0.0.1:7890 |
解决方法二:使用OPENAI API代理
1 | openai -b "https://api.openai-forward.com/v1" api chat_completions.create -m gpt-3.5-turbo -g user "Hello world" |
解决办法三:执行命令时指定代理(验证时没有生效)
1 | openai -p http://127.0.0.1:7890 -k sk-xxx api chat_completions.create -m gpt-3.5-turbo -g user "Hello world" |
使用-p
参数时,必须配合使用-k
参数,否则报错:
1 | usage: openai [-h] [-V] [-v] [-b API_BASE] [-k API_KEY] [-p PROXY [PROXY ...]] [-o ORGANIZATION] {api,tools,wandb} ... |
1、新建文件 hello.py
1 | import os |
2、执行 hello.py
1 | python hello.py |
返回值json结构:
1 | { |
测试文件,不要命名为 openai.py ,否则会报错:
1 | AttributeError: partially initialized module 'openai' has no attribute 'ChatCompletion' (most likely due to a circular import) |
Wechaty 是一个开源聊天机器人框架SDK,具有高度封装、高可用的特性,支持NodeJs, Python, Go 和Java 等多语言版本。在过去的4年中,服务了数万名开发者,收获了 Github 的 1w+ Star。同时配置了完整的 DevOps 体系并持续按照 Apache 的方式管理技术社区。
参考文档:
运行微信机器人有多种协议可以使用,有以下几种不同的协议方式:
每个协议都有不用的特点,如果不知道选什么,那么建议使用Padlocal协议。
Token 是 Wechaty 开放源代码项目中,所设计和支持的一种认证技术,可以使用第三方的 Wechaty Puppet Service 服务。Wechaty 社区中,提供 Puppet Service 的第三方,称之为 Wechaty Puppet Service Provider 。句子互动公司是 Wechaty PadPlus, WxWork, Donut 等 Puppet Service 的 Provider,提供对应 Puppet Service 的 Token ,实现开发者可以使用对应的协议服务。
在设置 Token 后,每个 Token 将可以使得一个微信号以 iPad 或 Mac 登录的方式进行登录,避免了既有网页端登录受限的问题。
每个 Token 可以使得一个微信号登录,如果希望多个号同时登录,需要获取多个 Token 。 但 Token 不与微信号绑定,即可以多个号不同时段轮流使用一个 Token 进行登录。
Wechaty 中的术语 Puppet 是用于实现协议插件的抽象类。插件是帮助控制 微信/Whatspp/TikTok 的组件,这就是我们称之为Puttet(傀儡)的原因。
参考文档:
申请 Padlocal Token 链接:Padlocal
免费试用Token可以使用7天,续费200元/月。建议成为Wechaty开发者,可以免费续期Token,参考文档How to be a Wechaty Contributor。
1、启动Gateway Docker
1 | git clone https://github.com/voidking/python-wechaty-template.git |
其中 puppet_padlocal_xxx
要替换成自己的Token。
最后一行的链接,是一个微信登录的二维码,python-wechaty连接gateway之后能够自动获取到这个链接并展示,以便我们登录。
当然,直接在浏览器中也能访问这个二维码,微信扫码可以登录,不过没什么用。
Gateway启动时,会生成一个WECHATY_TOKEN
,Gateway使用;同时会填入到 .env
文件中,给机器人使用。
运行自己的机器人代码时,也要用到这个 WECHATY_TOKEN
。
2、验证Gateway是否启动成功
1 | curl https://api.chatie.io/v0/hosties/$WECHATY_TOKEN |
1 | make bot |
报错:
1 | Traceback (most recent call last): |
这是因为,机器人连接Gateway Docker时,使用了外网IP,而外网IP的8080端口并未开放。
有两个解决办法:(1)开放外网IP的8080端口;(2)配置使用 WECHATY_PUPPET_SERVICE_ENDPOINT
变量。
这里选择第二种方法:
1 | docker run -it --name bot -d \ |
这里有个错误:Wechaty - ERROR - internal error <>
参考Wechaty - ERROR - internal error and failed to scan,忽略即可。
扫描登录,第一次登录时,会询问你登录的是 mac、windows还是ipad,这里要选择ipad。
登录成功后,半分钟左右,会自动退出,提示为了你的账号安全,请重新登录。
然后,再扫描登录,登录成功后还是会退出,后来再扫描二维码就没有反应了。。。
Padlocal Get Started,以失败告终。
Paimon相对于Padlocal,缺点很多:发送/接收图片、文件较慢;不支持接收/转发动图;不支持接收/发送语音消息;不支持转发音频/视频等。
不过,Paimon最大的优点就是简单,这就够了,关键是能用。
参考文档:
申请Token链接:Puppet Service: Paimon
免费试用Token可以使用7天,续费200元/月。建议成为Wechaty开发者,可以免费续期Token,参考文档How to be a Wechaty Contributor。
1、安装依赖
1 | pip install wechaty -i https://pypi.tuna.tsinghua.edu.cn/simple |
2、编写脚本 test.py
1 | import asyncio, os |
3、启动脚本
1 | python test.py |
使用微信号B扫码登录微信。
4、测试 ding dong
使用微信号A给微信号B发送一个ding
,可以收到自动回复的dong
,但是并没有接收到图片消息。
代码出现了报错:
经查,是因为教程中给的图片地址过期了,换成可用的地址后,可以正常接收到图片消息了。