0%

前言

本文汇总docker一些常用命令
一段日子不用,容易忘记,作为备忘录

wsl docker镜像移动

1
2
3
4
5
6
7
8
9
10
11
备份命令
wsl --export docker-desktop docker-desktop.tar
wsl --export docker-desktop-data docker-desktop-data.tar

删除命令
wsl --unregister docker-desktop
wsl --unregister docker-desktop-data

导入命令
wsl --import docker-desktop D:\work\docker\docker-desktop docker-desktop.tar
wsl --import docker-desktop-data D:\work\docker\docker-desktop-data docker-desktop-data.tar

busyboy

BusyBox 是一个集成了一百多个最常用 Linux 命令和工具(如 cat、echo、grep、mount、telnet 、ping、ifconfig 等)的精简工具箱,它只需要几 MB 的大小,很方便进行各种快速验证,被誉为“Linux 系统的瑞士军刀”。

1
docker run --name box1 -it --rm busybox sh

–rm 在退出容器时自动销毁该容器

docker compose 修改yml后更新容器

参考Docker Compose更新容器的几种方法
如果已经修改了docker-compose.yml文件,并且希望更新其中的某个容器,可以直接使用docker-compose up -d命令。该命令会更新docker-compose.yml中修改过的服务,并根据修改的设置进行重新配置。例如:

1
docker-compose up -d service-name

其中 service-name是需要更新的服务名。

dokcer 根据container 生成image

1
2
3
4
5
6
7
8
9
10
11
12
13
第一种方法:使用commit

//查看所有的容器
docker container ls -a

//suspicious_mcnulty是原容器name,gmk/centos-vim是新image的REPOSITORY
docker commit centos bivana/centos-env

//查看新镜像
docker image ls

docker push bivana/centos-env

docker 宿主机和容器拷贝文件

1
docker cp 本地路径 容器id或者容器名字:容器内路径

Failed to get D-Bus connection: Operation not permitted

docker 里的centos 如果要运行 systemctl 命令,需要以特权模式运行容器

1
docker run -d --name centos --privileged=true centos:7 /usr/sbin/init

docker 查看容器ip

1
docker inspect container_id

docker 进入当前容器

1
docker exec -it 容器id /bin/bash

前言

最近需要基于两台windows服务器(24核128G核80核128G)搭建数仓,数仓决定采用hadoop+spark的方式搭建。
由于操作系统是基于windows的,而数仓系统大多是基于linux,因此决定采用docker容器化进行安装。
万里长征,决定现行采用mysql安装踩点。

什么是docker

docker是一个用Go语言实现的开源项目,可以让我们方便的创建和使用容器,docker将程序以及程序所有的依赖都打包到docker container,这样你的程序可以在任何环境都会有一致的表现。

简单理解,docker通过容器化技术,将环境和应用程序一起打包运行,进而屏蔽环境差异,实现“build once, run everywhere”,同时实现快速部署。

docker的基本概念

  • dockerfile
  • image
  • container
    实际上你可以简单的把image理解为可执行程序,container就是运行起来的进程。

那么写程序需要源代码,那么“写”image就需要dockerfile,dockerfile就是image的源代码,docker就是”编译器”。

因此我们只需要在dockerfile中指定需要哪些程序、依赖什么样的配置,之后把dockerfile交给“编译器”docker进行“编译”,也就是docker build命令,生成的可执行程序就是image,之后就可以运行这个image了,这就是docker run命令,image运行起来后就是docker container。

docker的底层实现

docker基于Linux内核提供这样几项功能实现的:

NameSpace

我们知道Linux中的PID、IPC、网络等资源是全局的,而NameSpace机制是一种资源隔离方案,在该机制下这些资源就不再是全局的了,而是属于某个特定的NameSpace,各个NameSpace下的资源互不干扰,这就使得每个NameSpace看上去就像一个独立的操作系统一样,但是只有NameSpace是不够。

Control groups

虽然有了NameSpace技术可以实现资源隔离,但进程还是可以不受控的访问系统资源,比如CPU、内存、磁盘、网络等,为了控制容器中进程对资源的访问,Docker采用control groups技术(也就是cgroup),有了cgroup就可以控制容器中进程对系统资源的消耗了,比如你可以限制某个容器使用内存的上限、可以在哪些CPU上运行等等。
有了这两项技术,容器看起来就真的像是独立的操作系统了。

mysql镜像安装&运行

如果只是想跑起来,mysql docker镜像的安装和运行非常的简单

  1. docker hub中搜索mysql镜像,或者docker desktop搜索镜像,查找我们需要的mysql docker镜像,本人选择的tag为 8.0.33,tag对应的有pull命令。
  2. 运行 docker pull mysql:8.0.33下载之前搜索到的镜像。
  3. 运行命令docker run --name test -p 3306:3306 -e MYSQL_ROOT_PASSWORD=root -d mysql:8.0.33启动容器
    其中 -p 3306:3306 表示将容器内的3306桥接到本机的3306端口,-d mysql:8.0.33 为之前我们下载的镜像名称。
    要是不想命令,也可以直接在docker desktop上点击运行。

这样,一个mysql容器就运行了,但是这个容器只是试玩的,它存在以下几个问题

  • 资源未隔离【可能导致该容器占用完整个服务器的情况】
  • 存储未考虑【容器内的数据在容器重启后便会丢失】
  • 配置未优化【mysql默认配置无法满足生产要求】

因此在实际的生产部署中,我们需要解决上面三个情况

问题解决

资源隔离问题

资源方面,初步拍脑袋决定给mysql的容器为5G4核,网络的话,期望container能组成局域网,但是mysql服务最好在主机上有端口映射,这样主机可以对外提供服务。磁盘方面,则不进行限制了。

内存隔离

与操作系统类似,容器可以使用的内存包括两部分:物理内存和Swap【不理解的可以阅读深入理解swap交换分区理解及扩存了解下物理内存和swap的作用及关系】。

Docker通过下面两组参数来控制容器内存的使用量。

-m 或 –memory:设置内存的使用限额,例如:100MB,2GB。
–memory-swap:设置内存+swap的使用限额。
默认情况下,上面两组参数为-1,即对容器内存和swap的使用没有限制。如果在启动容器时,只指定-m而不指定–memory-swap, 那么–memory-swap默认为-m的两倍。

举例

1
2
3
4
5
# 允许该容器最多使用200MB的内存和100MB 的swap。
docker run -m 200M --memory-swap=300M ubuntu

# 容器最多使用200M的内存和200M的Swap
docker run -it -m 200M ubuntu

那么我们到底应该怎么设置呢?

参考redhat公司的推荐ch-swapspace

  • 内存小于4GB时,推荐不少于2GB的swap空间;
  • 内存4GB~16GB,推荐不少于4GB的swap空间;
  • 内存16GB~64GB,推荐不少于8GB的swap空间;
  • 内存64GB~256GB,推荐不少于16GB的swap空间。

本次mysql容器规划5G,那么推荐是不少于4GB,由于docker swap默认不得小于memory,因此就采用5GB,
因此最终的运行参数为

1
docker run  --name mysql  -m 5G --memory-swap=5G -p 3306:3306 -e MYSQL_ROOT_PASSWORD=root -d mysql:8.0.33

CPU 隔离

docker对cpu的隔离分为三种

  • CPU份额控制:-c或–cpu-shares
  • CPU核控制:–cpuset-cpus、–cpus
  • CPU周期控制:–cpu-period、–cpu-quota

具体这里就不进行展开了,可以阅读Docker资源(CPU/内存/磁盘IO/GPU)限制与分配指南进行了解。

本人直接采用了CPU核控制。

–cpus: 限制容器运行的核数;从docker1.13版本之后,docker提供了–cpus参数可以限定容器能使用的CPU核数。这个功能可以让我们更精确地设置容器CPU使用量,是一种更容易理解也常用的手段。

1
2
# 容器最多可以使用主机上两个CPU ,除此之外,还可以指定如 1.5 之类的小数。
docker run -it --rm --cpus=2 centos /bin/bash

由于本次规划的分配核数为4,因此最终的一个参数为

1
2
docker run  --name mysql --cpus=4  -m 5G --memory-swap=4G -p 3306:3306 -e MYSQL_ROOT_PASSWORD=root -d mysql:8.0.33

网络配置

docker网络相关的文章可以阅读全网最详细的Docker网络教程详解这篇文章进行了解。

对外提供服务,通过 -p 参数进行映射即可。

1
2
将容器内的3306端口映射到宿主机的1306端口
-p 1306:3306

容器的局域网设置

  1. 创建网络
    1
    docker network create -d macvlan  --subnet=172.16.1.0/24 --gateway=172.16.1.1 -o parent=eth0 dw-network
  2. 查看是否安装成功
    1
    docker network ls
    结果如下,可以看到dw-network网络创建完毕
    1
    2
    3
    4
    5
    6
    PS C:\Users\dell> docker network ls
    NETWORK ID NAME DRIVER SCOPE
    415ecf186909 bridge bridge local
    b01f87d53a20 dw-network macvlan local
    0ec71466bed7 host host local
    417fdf60fc8c none null local
  3. 启动容器并绑定固定ip
    1
    2
    3
    4
    5
    6
    7
    8
    9
    docker run --net=dw-network --name="test1" --ip=172.16.1.11 -e MYSQL_ROOT_PASSWORD=root -d mysql:8.0.33
    docker run --net=dw-network --name="test2" --ip=172.16.1.12 -e MYSQL_ROOT_PASSWORD=root -d mysql:8.0.33

    查看容器
    docker ps -a
    可以看到有两个容器已经启动
    CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
    569bb77f586e mysql:8.0.33 "docker-entrypoint.s…" 4 seconds ago Up 2 seconds test2
    224b3db441ae mysql:8.0.33 "docker-entrypoint.s…" 30 seconds ago Up 29 seconds test1
  4. 网络验证
    1
    2
    3
    4
    进入容器
    docker exec -it test1 /bin/bash
    docker exec -it test1 /bin/bash
    容器内telnet,yum都没,暂时就不验证了。。。。

磁盘隔离

Block IO 是另一种可以限制容器使用的资源。Block IO 指的是磁盘的读写,docker 可通过设置权重、限制 bps 和 iops 的方式控制容器读写磁盘的带宽

注:目前 Block IO 限额只对 direct IO(不使用文件缓存)有效。

这里就不进行权重限制了,后续有需求再进行配置。

如果使用的话,应该会采用权重策略。毕竟磁盘是最大的资源瓶颈。

存储持久化问题

docker内的文件都是临时的,当重启时,数据就会全部丢失。

但是docker贴心的提供了volume技术解决这一持久化问题。

即将宿主机的目录映射到容器目录。

mysql设计目录相关的,一个为/etc/my.cnf,一个为存储和日志,存储和日志默认配置都在/var/lib/mysql目录下,因此建立对应的volume映射

宿主机目录 容器目录
D:\work\docker\mysql/conf/my.cnf /etc/my.cnf
D:\work\docker\mysql/conf/ /etc/mysql
D:\work\docker\mysql/logs /var/log/mysql
D:\work\docker\mysql/data /var/lib/mysql

因此一个参数为

1
2
3
4
5
6
7
docker run --name test-mysql -p 3306:3306 \
-e MYSQL_ROOT_PASSWORD=root \
-v docker\mysql/conf/my.cnf:/etc/mysql/my.cnf \
-v docker\mysql/conf:/etc/mysql \
-v /hdocker\mysql/logs:/var/log/mysql \
-v docker\mysql/data:/var/lib/mysql \
-d mysql:8.0.33

mysql 性能配置

mysql的内存分配,参考

实战操作

铺垫了这么久,终于可以进行最后的实战操作记录了。

1.镜像下载

1
docker pull mysql:8.0.33

目录&文件准备

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
mkdir docker #docker总目录
mkdir docker/mysql # mysql容器预留目录
mkdir docker/mysql/conf # 配置持久化目录
mkdir docker/mysql/conf/conf.d # 配置持久化目录
mkdir docker/mysql/logs # 日志持久化目录
mkdir docker/mysql/data # 数据持久化目录
cat "" > docker/mysql/my-compose.yml
cat "" > docker/mysql/conf/my.cnf
编辑my.cnf,填入如下内容
[mysql]
default-character-set=utf8
[mysqld]
character-set-server=utf8
default-storage-engine=MyISAM
thread_cache_size=16
bulk_insert_buffer_size=8388608
concurrent_insert=AUTO
connect_timeout=10
delay_key_write=ON
delayed_insert_limit=100
delayed_insert_timeout=300
delayed_queue_size=1000
flush_time=0
innodb_adaptive_flushing=ON
innodb_adaptive_flushing_lwm=10
innodb_adaptive_hash_index=ON
innodb_adaptive_max_sleep_delay=150000
innodb_autoextend_increment=64
innodb_autoinc_lock_mode=2
#innodb_buffer_pool_dump_at_shutdown=ON
#innodb_buffer_pool_dump_pct=25
#innodb_buffer_pool_load_at_startup=ON
#innodb_change_buffer_max_size=25
#innodb_change_buffering=all
#innodb_checksum_algorithm=crc32
#innodb_cmp_per_index_enabled=OFF
#innodb_commit_concurrency=0
#innodb_compression_failure_threshold_pct=5
#innodb_compression_level=6
#innodb_compression_pad_pct_max=50
#innodb_concurrency_tickets=5000
#innodb_deadlock_detect=ON
#innodb_disable_sort_file_cache=OFF
innodb_flush_log_at_trx_commit=2
innodb_flush_method=O_DIRECT
innodb_flush_neighbors=0
innodb_flush_sync=ON
innodb_ft_cache_size=8000000
innodb_ft_enable_diag_print=OFF
innodb_ft_enable_stopword=ON
#innodb_ft_max_token_size=84
#innodb_ft_min_token_size=3

命令启动

创建网络

1
2
3
docker swarm init
docker network create -d overlay --attachable --subnet 172.16.1.0/24 --gateway 172.16.1.1 dw-network

容器启动

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
docker run  --name="mysql"  `
--net=dw-network `
--ip=172.16.1.11 `
--cpus=4 `
-m 5G `
--memory-swap=5G `
-v D:\work\docker\mysql/conf:/etc/mysql `
-v D:\work\docker\mysql/logs:/var/log/mysql `
-v D:\work\docker\mysql/data:/var/lib/mysql `
-p 1306:3306 `
-p 13060:33060 `
-e MYSQL_ROOT_PASSWORD=root `
-d mysql:8.0.33


docker run --name="mysql" `
--net=dw-network `
--ip=172.16.1.11 `
--cpus=4 `
-m 5G `
--memory-swap=5G `
-v D:\work\docker\mysql/conf:/etc/mysql `
-v D:\work\docker\mysql/logs:/var/log/mysql `
-v D:\work\docker\mysql/data:/var/lib/mysql `
-p 1306:3306 `
-p 13060:33060 `
-e MYSQL_ROOT_PASSWORD=root `
-d mysql:8.0.33



其中
-name="mysql" 容器名称为mysql
--net=dw-network #使用之前创建的 dw-network 网络
--ip=172.16.1.11 # 固定分配ip
--cpus=4 #分配4核cpu
-m 5G #分配5g物理内存
--memory-swap=5G #分配5g swap
-p 1306:3306 #将3306映射到主机的1306
-v D:\work\docker\mysql/conf/my.cnf:/etc/mysql/my.cnf #my.cnf配置文件
-v D:\work\docker\mysql/conf:/etc/mysql #mysql配置文件
-v D:\work\docker\mysql/logs:/var/log/mysql #日志目录
-v D:\work\docker\mysql/data:/var/lib/mysql #存储目录
-p 1306:3306 #将3306映射到主机的1306
-p 13060:33060 #将33060映射到主机的13060
-e MYSQL_ROOT_PASSWORD=root #指定mysql root默认密码
-d mysql:8.0.33 #启动的镜像

docker run -it –network dw-network –rm mysql 8.0.33 -hlocalhost -uroot -p
docker run -it –rm mysql 8.0.33 -hlocalhost -uroot -p

一些注意点

[Warning] World-writable config file ‘/etc/mysql/conf.d/my22.cnf’ is ignored.

这个报错,因为配置文件权限为777,mysql认为安全隐患较大,因此忽略。

解决方法
windows下本人未找到对应的linux权限
进入容器
修改文件权限

1
2
3
chmod 644 my.cnf


rpc error code = PermissionDenied desc = network dw-network not manually attachable.

当使用swarm的overlay网络,在该网络中运行容器时报“network xx not manually attachable”的错误

默认情况下使用docker network create -d overlay NET 创建的网络只能被swarm service使用,如果需要被独立的容器使用,需要添加–attachable选项

1
2
docker network create -d overlay --attachable my-attachable-overlay

总结

不知怎么的,以前docker看的云里雾里的东西,现在看起来也能理解了,一些踩坑点自己就能想到。

总的来说,使用docker安装应用,在有官方镜像的情况下,突出一个轻松加简单,我们只需自己做好资源的规划和配置即可。

build once,run anywhere,在docker这个技术下,很好的实现了。

香~

参考文章

背景

最近在windows上写博客,使用hexo 发布到linux服务器时,出现异常,此文记录踩坑指南。

过程

‘rsync’ �����ڲ����ⲿ���Ҳ���ǿ����еij����������ļ�

首先出现的问题是rsync,然后一堆乱码,具体的异常日志如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
'rsync' �����ڲ����ⲿ���Ҳ���ǿ����еij���
�������ļ�
FATAL {
err: Error: spawn rsync ENOENT
at notFoundError (D:\git\personal\test_blog\node_modules\cross-spawn\lib\enoent.js:6:26)
at verifyENOENT (D:\git\personal\test_blog\node_modules\cross-spawn\lib\enoent.js:40:16)
at cp.emit (D:\git\personal\test_blog\node_modules\cross-spawn\lib\enoent.js:27:25)
at ChildProcess._handle.onexit (node:internal/child_process:291:12) {
code: 'ENOENT',
errno: 'ENOENT',
syscall: 'spawn rsync',
path: 'rsync',
spawnargs: [
'--delete',
'--ignore-errors',
'-v',
'-az',
'-e',
'ssh -p 22',
'public/',
'root@xxxxx:/path'
]
}
} Something's wrong. Maybe you can find the solution here: %s https://hexo.io/docs/troubleshooting.html
PS D:\git\personal\test_blog>

关键的错误信息乱码了。。。
第一步需要解决的就是将错误信息以正确的结果进行展示。

由于本人使用vscode,默认使用powershell进行,因此直接搜索windows powbershell 修改查看编码,得到了解决windowspowershell中文显示问号及乱码问题这篇文章,在重启后确实有用,而且将整个系统编码默认设置为utf-8编码,可以减少很多问题,因此果断采用。

具体操作如下
打开 控制面板—>区域—>管理—>更改系统区域设置
勾选:使用Unicode UTF-8提供全球语音支持

设置完成后重启电脑生效,再次尝试hexo g -d编译并部署,错误编码显示正常,得到以下错误

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
INFO  Start processing
INFO Files loaded in 2.58 s
INFO 0 files generated in 3.25 s
INFO Deploying: rsync
'rsync' is not recognized as an internal or external command,
operable program or batch file.
FATAL {
err: Error: spawn rsync ENOENT
at notFoundError (D:\git\personal\test_blog\node_modules\cross-spawn\lib\enoent.js:6:26)
at verifyENOENT (D:\git\personal\test_blog\node_modules\cross-spawn\lib\enoent.js:40:16)
at cp.emit (D:\git\personal\test_blog\node_modules\cross-spawn\lib\enoent.js:27:25)
at ChildProcess._handle.onexit (node:internal/child_process:291:12) {
code: 'ENOENT',
errno: 'ENOENT',
syscall: 'spawn rsync',
path: 'rsync',
spawnargs: [
'--delete',
'--ignore-errors',
'-v',
'-az',
'-e',
'D:\\soft\\install\\cwrsync_6.2.8_x64_free\\bin\\ssh -p 22',
'public/',
'root@www.test.com:/www/test_blog'
]
}
} Something's wrong. Maybe you can find the solution here: %s https://hexo.io/docs/troubleshooting.html

‘rsync’ is not recognized as an internal or external command

其实这个错误说的挺明显的了,rsync无法识别,于是搜索windows hexo 'rsync' is not recognized as an internal or external command,得到了使用Hexo发布博客(Windows环境),了解到windows系统默认没有rsync,因此需要下载安装。

rsync下载的官网地址为: https://www.itefix.net/cwrsync
该网址可能需要梯子,没有的就自行从网上搜索啥的第三方下载吧.

进入官网的具体下载路径为free/free software/cwrsync-rsync client for windows

之后进入下载页面,选择download下载需要的版本.

本人直接下载了最新版本,之后直接解压,配置对应的环境变量,将rysnc/bin添加到path环境变量中

最后再次尝试,你讲得到以下错误

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
INFO  Start processing
INFO Files loaded in 2.19 s
INFO 0 files generated in 3.11 s
INFO Deploying: rsync
root@www.test.com's password:
rsync: connection unexpectedly closed (0 bytes received so far) [Receiver]
rsync error: error in rsync protocol data stream (code 12) at io.c(226) [Receiver=3.1.2]
rsync: connection unexpectedly closed (0 bytes received so far) [sender]
rsync error: error in rsync protocol data stream (code 12) at io.c(231) [sender=3.2.7]
FATAL {
err: Error: rsync: connection unexpectedly closed (0 bytes received so far) [Receiver]
rsync error: error in rsync protocol data stream (code 12) at io.c(226) [Receiver=3.1.2]
rsync: connection unexpectedly closed (0 bytes received so far) [sender]
rsync error: error in rsync protocol data stream (code 12) at io.c(231) [sender=3.2.7]

at ChildProcess.<anonymous> (D:\git\personal\test_blog\node_modules\hexo-deployer-rsync\node_modules\hexo-util\lib\spawn.js:36:19)
at ChildProcess.emit (node:events:513:28)
at cp.emit (D:\git\personal\test_blog\node_modules\cross-spawn\lib\enoent.js:34:29)
at maybeClose (node:internal/child_process:1091:16)
at ChildProcess._handle.onexit (node:internal/child_process:302:5) {
code: 12
}
} Something's wrong. Maybe you can find the solution here: %s https://hexo.io/docs/troubleshooting.html

err: Error: rsync: connection unexpectedly closed (0 bytes received so far) [Receiver]

于是网上搜索 hexo windows err: Error: rsync: connection unexpectedly closed (0 bytes received so far) [Receiver] 搜到了Cygwin 使用rsync 报错解决这篇文章,经过验证后,确认是因为rsync 的ssh和系统默认的ssh冲突导致的,具体原因这里就不深入了。

验证

首先打开cmd,查看输入where rsync查看位置,显示如下

1
2
C:\Users\ivan>where rsync
D:\soft\install\cwrsync_6.2.8_x64_free\bin\rsync.exe

可以看到rsync使用的是我们之前系统环境变量设置的rsync

接着输入where ssh查看,显示如下

1
2
3
C:\Users\ivan>where ssh
C:\Windows\System32\OpenSSH\ssh.exe
D:\soft\install\cwrsync_6.2.8_x64_free\bin\ssh.exe

可以看到ssh默认有两个,系统自带的openssh下的ssh和rsync自带的ssh。

由于rsync实际要调用ssh,而在调用ssh时,系统的open ssh优先,实际调用了open ssh,没有调用到rsync自带的ssh,导致版本错配,进而发生了rsync error: error in rsync protocol data stream (code 12) at io.c(231)这个异常。

解决方案

此时解决思路有以下几种

  1. 修改环境变量,删除openssh的环境变量,这样就不会错配
  2. 在hexo deploy调用rsync命令时,将ssh路径写死。

由于openssh影响较大,不敢删除这个环境变量,因此采用了方案2.

hexo deploy的rsync是通过 node_modules/hexo-deployer-rsync来实现的,查看lib/deployer.js,发现有ssh关键字,将这个改为绝对路径即可。

将相对ssh修改为绝对ssh

1
2
3
4
5
6
7
8
9
10
11

if (args.port && args.port > 0 && args.port < 65536) {
params.splice(params.length - 2, 0, '-e');
params.splice(params.length - 2, 0, 'ssh -p ' + args.port);
}
修改为
if (args.port && args.port > 0 && args.port < 65536) {
params.splice(params.length - 2, 0, '-e');
params.splice(params.length - 2, 0, 'D:\\soft\\install\\cwrsync_6.2.8_x64_free\\bin\\ssh -p ' + args.port);
}

效果

最后再来尝试,那么你将得到以下错误

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
INFO  Start processing
INFO Files loaded in 2.58 s
INFO 0 files generated in 3.9 s
INFO Deploying: rsync
Host key verification failed.
rsync: connection unexpectedly closed (0 bytes received so far) [sender]
rsync error: error in rsync protocol data stream (code 12) at io.c(231) [sender=3.2.7]
FATAL {
err: Error: Host key verification failed.
rsync: connection unexpectedly closed (0 bytes received so far) [sender]
rsync error: error in rsync protocol data stream (code 12) at io.c(231) [sender=3.2.7]

at ChildProcess.<anonymous> (D:\git\personal\test_blog\node_modules\hexo-deployer-rsync\node_modules\hexo-util\lib\spawn.js:36:19)
at ChildProcess.emit (node:events:513:28)
at cp.emit (D:\git\personal\test_blog\node_modules\cross-spawn\lib\enoent.js:34:29)
at maybeClose (node:internal/child_process:1091:16)
at ChildProcess._handle.onexit (node:internal/child_process:302:5) {
code: 12
}
} Something's wrong. Maybe you can find the solution here: %s https://hexo.io/docs/troubleshooting.html

Error: Host key verification failed.

这个错误其实就想对简单了,host不被信任,直接进入rsync安装的bin目录下
输入

1
ssh root@xxxx

然后认证yes就可以了。

之后再次尝试,你将得到如下入错……

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
INFO  Start processing
INFO Files loaded in 2.1 s
INFO 0 files generated in 3.04 s
INFO Deploying: rsync
Permission denied, please try again.
Permission denied, please try again.
root@www.test.com: Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password).
rsync: connection unexpectedly closed (0 bytes received so far) [sender]
rsync error: error in rsync protocol data stream (code 12) at io.c(231) [sender=3.2.7]
FATAL {
err: Error: Permission denied, please try again.
Permission denied, please try again.
root@www.test.com: Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password).
rsync: connection unexpectedly closed (0 bytes received so far) [sender]
rsync error: error in rsync protocol data stream (code 12) at io.c(231) [sender=3.2.7]

at ChildProcess.<anonymous> (D:\git\personal\test_blog\node_modules\hexo-deployer-rsync\node_modules\hexo-util\lib\spawn.js:36:19)
at ChildProcess.emit (node:events:513:28)
at cp.emit (D:\git\personal\test_blog\node_modules\cross-spawn\lib\enoent.js:34:29)
at maybeClose (node:internal/child_process:1091:16)
at ChildProcess._handle.onexit (node:internal/child_process:302:5) {
code: 12
}
} Something's wrong. Maybe you can find the solution here: %s https://hexo.io/docs/troubleshooting.html

err: Error: Permission denied, please try again.

这个异常其实就比较常见了,就是认证失败
通过查看spawn.js, deploy 最终使用的rsync命令大概长这样

1
rsync --delete --ignore-errors -v -az -e "D:\\soft\\install\\cwrsync_6.2.8_x64_free\\bin\\ssh -p 22" public/ root@www.test.com:/www/test_blog

如果直接使用这个命令,powbershell其实是会有一个输入框要你输入密码的,其实本人在hexo deploy在mac电脑上使用时也是有的,但是在windows下不知道为什么就没了。

这里就不走这条路径了,直接采用无秘钥登录,即通过ssh进行登录。

首先进入rsync_home/bin

运行ssh-keygen,熟悉sshd的小伙伴一定知道这就是个秘钥生产。

直接一路enter键盘,默认的生产文件路径为

1
2
3
~/.ssh/

C:\Users\ivan\.ssh>


id_rsa.pub的文本拷贝到服务器上的authorized_keys即可

这里不熟悉的小伙伴可以自行搜索 liunux ssh无秘钥登录。

最后再来hexo g -d

1
2
3

sent 713,559 bytes received 438,308 bytes 74,314.00 bytes/sec
total size is 58,929,007 speedu

成功部署,撒花完结?不存在的。。。。

这时候访问域名,出现了 403

403 问题解决

查看nginx日志

1
2
3

2023/04/28 11:11:42 [error] 23279#23279: *28 "/www/test_blog/index.html" is forbidden (13: Permission denied), client: 115.236.79.172, server: www.test.com, request: "GET / HTTP/1.1", host: "www.test.com"
2023/04/28 11:11:42 [error] 23279#23279: *28 open() "/www/test_blog/favicon.ico" failed (13: Permission denied), client: 115.236.79.172, server: www.test.com, request: "GET /favicon.ico HTTP/1.1", host: "www.test.com", referrer: "http://www.test.com/"

权限不足。。。
查看使用rsync同步上来的文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

drwxrwx--- 3 197609 197121 4096 Apr 27 11:21 2020
drwxrwx--- 4 197609 197121 4096 Apr 27 11:21 2021
drwxrwx--- 11 197609 197121 4096 Apr 27 11:21 2022
drwxrwx--- 5 197609 197121 4096 Apr 27 11:21 2023
drwxrwx--- 2 197609 197121 4096 Apr 27 11:21 about
drwxrwx--- 7 197609 197121 4096 Apr 27 11:21 archives
drwxrwx--- 6 197609 197121 4096 Apr 27 11:21 categories
drwxrwx--- 2 197609 197121 4096 Apr 27 11:21 css
drwxrwx--- 3 197609 197121 4096 Apr 27 11:21 images
-rwxrwx--- 1 197609 197121 304656 Apr 27 16:51 index.html
drwxrwx--- 4 197609 197121 4096 Apr 27 11:21 js
drwxrwx--- 11 197609 197121 4096 Apr 27 11:21 page
-rwxrwx--- 1 197609 197121 1239294 Apr 28 11:22 search.xml
-rwxrwx--- 1 197609 197121 16138 Apr 27 16:51 sitemap.txt
-rwxrwx--- 1 197609 197121 40537 Apr 28 10:02 sitemap.xml
drwxrwx--- 60 197609 197121 4096 Apr 27 11:21 tags

其他组的权限为0.。。。而nginx是使用nginx用户运行的,也就是说没有可读权限导致的报错。真是个悲伤的故事。

于是搜索 rsync windows liunux 权限问题,得到了cygwin rsync windows permissions,该文指出了解决的三种方式。

  • 使用rsync的”–chmod”选项来指定同步后文件的权限
  • 如果需要保留文件所有者和权限等信息,可以使用”-p”选项
  • 使用”–no-perms”选项来忽略源文件的权限信息

最终本人直接选用了第一种

在搜索hexo deploy的文档后,未发现关于–chmod的选项,因此继续采用修改js的方法。

修改deployer.js,增加 params.unshift('--chmod=ugo=rx');用于增加权限设置,需求读写。

1
2
3
4
5
6
7
8
9
10
11
修改前
if (args.verbose) params.unshift('-v');
if (args.ignore_errors) params.unshift('--ignore-errors');
if (args.delete) params.unshift('--delete');
if (args.args) params.unshift(args.args);
修改后
params.unshift('--chmod=ugo=rx');
if (args.verbose) params.unshift('-v');
if (args.ignore_errors) params.unshift('--ignore-errors');
if (args.delete) params.unshift('--delete');
if (args.args) params.unshift(args.args);

最后执行hexo g -d
成功访问,真正的完结撒花

总结

总的来说,在windows上使用hexo rsync deploy部署到服务器的踩坑点还是有点多的,有点类似俄罗斯套娃,踩了一个还有一个。

最主要的其实就是编码啊,rsync的环境变量,权限这些。

祝大家少踩坑。

参考文章

解决windowspowershell中文显示问号及乱码问题
使用Hexo发布博客(Windows环境)
Cygwin 使用rsync 报错解决

场景描述

最近有个需求需要处理下从南京统计局下载的宏观数据pdf,需要将pdf中的表格数据提取出来进一步加工,样例格式如下。

可以看到格式还是比较标准的,我本来以为网上随便一搜python pdf table提取,便能简单的处理大功搞成,然而实际还是踩了不少坑,因此还是记录下。

具体的pdf这里就不展示了,以camelot的样例pdf为例,下载可以点击此链接

技术选型

首先,我确实是在网上搜索python pdf table extract,基本很快就锁定了 pdfplumber,然而在一通操作后,发现pdfplumber的默认识别不太准确,一个很大的原因是pdf的表格很多并不是以标准的线画的,虽然可以使用text方式识别+定制化的一些参数,但是调整太累了,后面本人就放弃了。pdfplumber的官方文档参见pdfplumbergit地址,里面对于一些对象及配置有详尽的描述。另外,知乎的这篇关于python提取pdf不规则表格写得非常不错,里面有讲碰到不规则表格,提取内容错误时,如何利用 debug_tablefinder 画出红线,进而调整进阶参数以优化提取效果。

在pdfplumber碰壁后,继而了解到camelot在无线框表格上效果更好,因此果断尝试,不得不说最终的效果还是不错的。

camelot的git地址参见camelot git 地址,相对来说,camelot的文档就没有那么详尽了,不得不说是一个遗憾。

环境安装

camelot的安装挺坑的。。。,以下只是本人的安装和解决方案。

1. camelot安装

千万不要直接使用pip install camelot进行安装,真正的命令为

1
2
pip install camelot-py
pip install opencv-python

安装完后,本人碰到了

1
Python-camelot (Error: GhostscriptNotFound 

这个问题,参考网上的,到ghostscript官网下载对应的版本。

本人为windows,因此下载了ghostscript-10.01.1.tar.xz,解压完需要添加

1
2
C:\Program Files\gs\gs9.26\bin
C:\Program Files\gs\gs9.26\lib

到path下,不然依然会报错。

最后,你需要安装下ghostscript

1
pip install ghostscript

不然会得到以下错误

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
PS C:/Users/ivan/AppData/Local/Programs/Python/Python311/python tjj_hgsj_py/nj_tjj.py
Traceback (most recent call last):
File "tjj_hgsj_py\nj_tjj.py", line 20, in <module>
tables= camelot.read_pdf(pdfFilePath)####从1开始计数
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\ivan\AppData\Local\Programs\Python\Python311\Lib\site-packages\camelot\io.py", line 113, in read_pdf
tables = p.parse(
^^^^^^^^
File "C:\Users\ivan\AppData\Local\Programs\Python\Python311\Lib\site-packages\camelot\handlers.py", line 176, in parse
t = parser.extract_tables(
^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\ivan\AppData\Local\Programs\Python\Python311\Lib\site-packages\camelot\parsers\lattice.py", line 421, in extract_tables
self.backend.convert(self.filename, self.imagename)
File "C:\Users\ivan\AppData\Local\Programs\Python\Python311\Lib\site-packages\camelot\backends\ghostscript_backend.py", line 36, in convert
import ghostscript
ModuleNotFoundError: No module named 'ghostscript'

至此,camelot安装完成。

代码实现

具体代码可以查看 camelot_pdf_table_parse

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import os
import pandas as pd
import camelot


# 读取pdf文件,获取pdf的表格数据,并保存为csv
pdfFilePath="foo.pdf"
csvFilePath="table.csv"
separate_coma=","

# 使用camelot解析table,all为解析所有的pdf page
tables= camelot.read_pdf(pdfFilePath,pages='all')
# 将所有的table 拼接为一个df
table_df=tables[0].df
for i in range(1,len(tables)):
table_df=table_df._append(tables[i].df)
# 加入自定义字段
table_df['report_date']='2023-02-28'
# 调整顺序,放入第一个
table_df.insert(0,'report_date',table_df.pop('report_date'))
print(table_df)
# 保存为csv文件,为后续入库方便,去除index
table_df.to_csv(csvFilePath,index=None)
print("foo table data finished")

整体代码就想对比较简单了,但是也有一些细节需要处理,方能最后使用,比如

  • 读取所有page,camelot默认只读取pdf的第一页,因此需要all参数。
  • 拼接dataframe
  • 新增自定义列
  • 保存csv去除行号

实现效果

pdf原始表格

提取后的dataframe效果

1
2
3
4
5
6
7
8
  report_date             0            1                2                     3                  4                  5                 6
0 2023-02-28 Cycle \nName KI \n(1/km) Distance \n(mi) Percent Fuel Savings
1 2023-02-28 Improved \nSpeed Decreased \nAccel Eliminate \nStops Decreased \nIdle
2 2023-02-28 2012_2 3.30 1.3 5.9% 9.5% 29.2% 17.4%
3 2023-02-28 2145_1 0.68 11.2 2.4% 0.1% 9.5% 2.7%
4 2023-02-28 4234_1 0.59 58.7 8.5% 1.3% 8.5% 3.3%
5 2023-02-28 2032_2 0.17 57.8 21.7% 0.3% 2.7% 1.2%
6 2023-02-28 4171_1 0.07 173.9 58.1% 1.6% 2.1% 0.5%

最终的csv文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
report_date,0,1,2,3,4,5,6
2023-02-28,"Cycle
Name","KI
(1/km)","Distance
(mi)",Percent Fuel Savings,,,
2023-02-28,,,,"Improved
Speed","Decreased
Accel","Eliminate
Stops","Decreased
Idle"
2023-02-28,2012_2,3.30,1.3,5.9%,9.5%,29.2%,17.4%
2023-02-28,2145_1,0.68,11.2,2.4%,0.1%,9.5%,2.7%
2023-02-28,4234_1,0.59,58.7,8.5%,1.3%,8.5%,3.3%
2023-02-28,2032_2,0.17,57.8,21.7%,0.3%,2.7%,1.2%
2023-02-28,4171_1,0.07,173.9,58.1%,1.6%,2.1%,0.5%

踩坑点及解决方法

Python-camelot (Error: GhostscriptNotFound

需要安装ghostscript
ghostscript官网下载对应的版本。

ModuleNotFoundError: No module named ‘ghostscript’

安装完ghostscript程序后,还需安装ghostscript模块

1
pip install ghostscript

camelot只能读取pdf的第一页

参数需要填all

1
2
tables= camelot.read_pdf(pdfFilePath,pages='all')

Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub.

Quick Start

Create a new post

1
$ hexo new "My New Post"

More info: Writing

Run server

1
$ hexo server

More info: Server

Generate static files

1
$ hexo generate

More info: Generating

Deploy to remote sites

1
$ hexo deploy

More info: Deployment

引言

本人为个人常用的一些命令汇总

/var/log/secure

secure为linux服务器的登录日志,公网默认22端口具有极大的风险。

通过以下命令,可以大致分析当前安全现状,为安全加固提供依据。

1
2
3
4
5
6
7
8
1、哪些IP在爆破主机的root帐号:    
grep "Failed password for root" /var/log/secure | awk '{print $11}' | sort | uniq -c | sort -nr

2、哪些IP在爆破用户:
grep "Failed password" /var/log/secure|perl -e 'while($_=<>){ /from(.*?) port/; print "$1\n";}'|sort -nr|uniq -c |sort -nr

3、爆破用户名字典
grep "Failed password" /var/log/secure|perl -e 'while($_=<>){ /for(.*?) from/; print "$1\n";}'|sort -nr|uniq -c |sort -nr

修改ssh端口

linux默认的端口为22
修改端口的配置文件地址为

1
vi /etc/ssh/sshd_config

找到如下位置

1
# Port 22

默认的端口为22,且是注释的,将#号去掉,端口修改为自己想要的端口
重启服务

1
service sshd restart

登录方法为

1
ssh root@xxx -p port

linux 参数解析

参考linux-shell脚本中的参数解析

大数据之路,不得不说是大数据的神书,本次再次阅读,又有了不同的收获。

问题&需求

hexo 博客默认的首页文章排序为博客发布日期的倒序,有些时候期望将一些高质量的博文置顶,方便访客查看。

解决方案选择

上网随便google了下,发现有现成的解决方案
网上的解决方案有两种

  1. 修改generator.js
  2. 使用现成的插件。

修改generator.js

该方案需要修改核心的js代码,原理就是通过在front-matter中设置需要置顶文章的top值,然后在generator时根据top排序。

该方案的出处应该是解决Hexo博客文章置顶问题这篇博文【本人未验证哈】,其他的应该都是从这篇博文中炒出来的。

由于该方案是早期的方案,后面已经有更成熟的插件方案,具体实现这里就不说了。

使用现成插件

首先,插件的github项目名称和地址为hexo-generator-index,目前的最新版本已经到3.0了,是2022-10-16 release的。

网上很多文章的配置其实都已经过时了,比如使用top进行配置的,最新的使用方法还是建议大家直接阅读github项目上的readme说明,上面有现成的方法。

通过简单的了解,本人最后选定hexo-generator-index作为博客的置顶方案。

hexo-generator-index 安装使用和效果

  1. 通过如下命令安装
    1
    npm install hexo-generator-index --save
  2. 通过在文章的front-matter中添加sticky属性进行使用,其中sticky数值越大,优先级越高。
    1
    2
    3
    4
    5
    ---
    title: Hello World
    date: 2013/7/13 20:46:25
    sticky: 100
    ---
    本人的一个效果如下图所示

可以看到,写了stikcy的文章已经置顶了,切有了一个置顶的标签。

参考文章

Hexo nexT主题之文章置顶
解决Hexo博客文章置顶问题
hexo-generator-index

2022 总结

基准

2022年
上证指数下跌 15.13%
沪市300指数下跌 21.63%

个人

2022年度收益率 -2.4%,同期跑赢上证12.73%,沪深300 19.23%。

扣除打新收益。 121187
2022年度收益率 -15.65%,同期跑输上证0.52%,跑赢沪深300指数 5.98%

2022年通过打新股收益率14832.96,打新债收益1228.19 合计16061.15.

累计

年份 个人收益率 上证 上证超额 沪深300 沪深300超额
2021 7.44% 4.8% 2.64% -5.2% 12.64%
2022 -2.4% -15.13% 12.73% -21.63% 19.23%
复合年华 2.4% -5.69% 7.57% -13.81% 15.89%

个人总结

2022年总得来说,陈善可乏,扣除打新收益,基本就是跟随大盘随波逐流,更加证明了我没啥投资天赋。

一个创新是在11月的时候引入了量化投资,个人也打通了东方财富的自动化接口,实现了程序化交易,并将可转债策略放入实盘。

做的好的部分,学会了分散持仓,个人的选股也没啥大问题。

做的不好的地方

  1. 对于看好的股票,还是买贵了,个人守不住空仓,这也是后面引入程序交易的原因,摒弃一切个人因素,按计划执行。
  2. 对于基本面的研究没有更近一步。

2023 目标

2023年,估计仍然是不容乐观的一年,当然,市场应该是见底了的,应该是底部徘徊的一年。

2023年,个人应该是全年采用可转债策略量化交易,期间可能会进行一些策略改正。

收益期望的话,限定个7%吧。

前言

22年12月31日想做的事情,24年6月25日,补上。。。。

策略目标

根据自己分析的股票池做资产组合,根据分析的目标价位,结合当前估值给定仓位,日内做仓位动态调仓,避免长期坐过山车,也避免自己天天看股价导致手贱买卖,免除自己手动操作。

核心思路

估值定仓,即给定一个股票的目标价格,根据价格高低给与仓位。

个股分析的结果如下

股票代码 股票名称 版本日期 当前市值 乐观只是 悲观市值 分析备注
60000 股票A 2024-06-25 80 160 30 xxxx
60000 股票B 2024-06-25 30 100 5 xxx

仓位策略

part1 个股仓位=单股最高仓位*单股计划仓位

其中,单股最高仓位为单股占总资产最高的比例
单股计划仓位为根据当前的市值和目标,计划的仓位比例。

part1 单股最高仓位

确认性高的,20%
确认性较低的,10%
风险博弈的,5%

part2 仓位

整体差值分为两部分,前50%权重为1,后50%权重为2。

仓位=(乐观价格-当前价格)/(乐观价格-悲观价格)

比如一个股票目标价是100,悲观价为50,当前价98,那么当前仓位为:
(100-98)/(100-50)/1.5=0.026,给与2.6的仓位。

比如一个股票目标价是100,悲观价为50,当前价55,那么当前仓位为:
((100-55)/(100-50)-0.5)/0.5*0.666+0.3333=0.8666,给与86.7%的仓位。

part3 买入

根据仓位计算出价格,动态买卖,实现低买高卖。