1. 概述

  • 通过部署Docker Registry,可实现自建Docker私有仓库。
  • 自建Docker私有仓库,主要是方便内部分发或部署项目。如果只有一个服务器,可以直接build镜像,且不建私有仓库。
  • 各大厂商有提供免费的私有仓库服务,可以不用自建。

官方相关文档:

2. 部署

  • 假设在IP为192.168.0.1的服务器上部署。
  • Docker Registry采用端口5000docker-registry-ui采用端口80
  • 建议使用Docker Compose方式进行部署。
  • 为了方便管理(主要是执行“删除”操作),同时部署了可视化操作的Web界面。
  • 由于是内部部署,Docker Registry没有配置用户管理(包括用户的身份验证、权限管理之类)。
  • Registry的所有配置项,均可通过环境变量设置。相关的完整配置项说明,详见:Configuring a registry

部署Registry的docker-compose.yaml文件,参考如下:

version: '3.8'

services:
  registry-server:
    image: registry:latest
    #container_name: registry-server
    restart: always
    environment:
      - REGISTRY_STORAGE_DELETE_ENABLED: true
  volumes:
    - ./registry:/var/lib/registry

  registry-ui:
    image: joxit/docker-registry-ui:latest
    #container_name: registry-ui
    restart: always
    ports:
      - 80:80
    environment:
      - SINGLE_REGISTRY=true
      - REGISTRY_TITLE=Docker Registry UI
      - DELETE_IMAGES=true 
      - SHOW_CONTENT_DIGEST=true 
      - NGINX_PROXY_PASS_URL=http://registry-server:5000
      - SHOW_CATALOG_NB_TAGS=true
      - CATALOG_MIN_BRANCHES=1
      - CATALOG_MAX_BRANCHES=1
      - TAGLIST_PAGE_SIZE=100
      - REGISTRY_SECURED=false
      - CATALOG_ELEMENTS_LIMIT=1000

3. 上传镜像

给镜像设置名称和tag,然后执行docker push上传。其中镜像名称需要以Registry地址(IP或域名)+端口作为前缀。

示例命令如下:

# 给镜像设置tag
docker tag <镜像名称>:<tag> 192.168.0.1:5000/<镜像名称>:<tag>

# 上传镜像
docker push 192.168.0.1:5000/<镜像名称>:<tag>

4. 下载镜像

4.1. 修改Docke配置文件。

一般Linux上,Docker服务的配置文件在/etc/docker/daemon.jsoninsecure-registries添加Docker Registry服务,例如:

{
    "insecure-registries":["192.168.0.1:5000"]
}

修改后需要使用配置生效。可重启本机Docker服务,或执行热更新操作。例如:

# 重启本机Docker服务
sudo systemctl restart docker

# Docker配置文件热更新
sudo kill -SIGHUP $(pidof dockerd)

4.2. 从自建私有仓库下载镜像

docker pull 192.168.0.10:5000/<镜像名称>:<tag>

5. 仓库管理

一般通过docker-registry-ui(即http://192.168.0.1/),对私有仓库的镜像进行查看、删除。

Docker Registry本身提供了接口,用于管理其存储的镜像。

最近使用了MySQL 8的主从复制,利用数据同步,实现数据备份。

1. 概述

关于MySQL主从复制的原理和各种部署方式,参考:看完这篇还不懂 MySQL 主从复制,可以回家躺平了~。本文采用“一主一从”方式部署。

参考文章:

官方文档:

注意:从MySQL 8.0.22开始,大量涉及“SLAVE”的配置和命令,都改为“REPLICA”字样,详见官网说明。

2. 主服务器配置

主服务器是安装在Debian 12的MySQL 8,假设其IP地址为192.168.0.100。修改MySQL的配置文件/etc/mysql/conf.d/mysqld.cnf,在[mysqld]下添加以下配置。保存配置文件后重启MySQL服务。

[mysqld]
# 主从复制,设为主服务器
# 服务器ID
server-id = 1
# 开启二进制日志。事务提交时写日志到对应文件
log-bin = mysql-bin
# 日志过期删除的天数,延迟严重的话会导致日志文件占用磁盘
expire_logs_days = 14

利用mysql命令,连上MySQL主服务器,并执行以下语句。注意: MySQL 8 默认身份验证插件是caching_sha2_password,详见变量default_authentication_plugin的配置。

-- 创建用户,提供给从服务器访问
CREATE USER 'repl'@'%' IDENTIFIED WITH caching_sha2_password BY 'password';
-- 授权用户拥有所有数据库表的同步数据权限
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';

再执行以下语句,显示主服务器的配置,记下FilePosition的值。

SHOW MASTER STATUS\G;

3. 从服务器配置

从服务是安装在Debian 12的MySQL 8,假设其IP地址为192.168.0.101。修改MySQL配置文件/etc/mysql/conf.d/mysqld.cnf,在[mysqld]下添加以下配置。保存配置文件后重启MySQL服务。

# 主从复制,设为从服务器
# 服务器ID
server-id = 2
# 同步的数据库。多个数据库需配置多行
#replicate-do-db = db1
#replicate-do-db = db2
# 服务重启后自动开始同步数据,默认OFF
#skip-replica-start = false

利用mysql命令,连上MySQL从服务器,并执行以下语句。

  • 由于主服务器的身份验证插件采用caching_sha2_password,从服务器需要配置GET_SOURCE_PUBLIC_KEY=1才能通过身份验证。
  • SOURCE_LOG_FILE对应主服务器的File的值。
  • SOURCE_LOG_POS对应主服务器的Position的值。
-- 从服务器配置
STOP REPLICA;

CHANGE REPLICATION SOURCE TO SOURCE_HOST='192.168.0.100'
    ,SOURCE_PORT=3306
    ,SOURCE_USER='repl'
    ,SOURCE_PASSWORD='password'
    ,SOURCE_LOG_FILE='mysql-bin.000001'
    ,SOURCE_LOG_POS=123
    ,GET_SOURCE_PUBLIC_KEY=1
    ;

START REPLICA;

执行以下语句,查看从服务器的状态,检查从服务器是否正常运行。如果Replica_IO_RunningReplica_SQL_Running都显示Yes,则表示正常运行。

SHOW REPLICA STATUS\G;

整理一下在广州的City Walk路线,顺便记录一下带娃经历。

1. 概述

一般问广州本地人有啥好玩,都说没啥好玩。只缘身在此山中?因此,以非广州的广东人身份聊下这个话题。作为周边城市的居民,我觉得广州非常适合周末逛逛、带娃,切换一下生活空间,也给孩子涨涨见识。

2. 交通

总的来说,外地游客不建议自驾,并尽量乘坐公共交通工具。除非确认目的地有停车位置,并且确认行车路线不堵车。

2.1. 地铁

建议日程规划以地铁为主,虽然换乘站点或热门站点有点挤,但不会堵车。

2.2. 船

注意不是夜游珠江那种本地人都不坐的游船。最近才发现广州的码头之间有“水上巴士”,票价最低2元/人,小孩1米3以下免费。具体航班详见微信公众号“广州客轮”。可以在旅途增添乐趣。

2.3. 其它

比如共享单车。

3. 路线

3.1. 北京路步行街

地铁站[公园前] -> 动漫星城 -> 北京路 -> 天字码头

  • 动漫星城,二次元综合商城。经常周末出现cosplay聚会。
  • 北京路,商业步行街。个人比较喜欢 Baleno 特价店。
  • 北京路宋朝古迹,宋朝的地砖。
  • 大佛寺,据说千年历史。
  • 天字码头,可坐水上巴士。

3.2. 一德路

地铁站[海珠广场] -> 万菱广场 -> 一德路 -> 石室圣心大教堂 -> 清平路 -> 广州文化公园 -> 沙面岛

  • 海珠广场。印象中没逛过这广场。
  • 万菱广场,文具玩具商场。
  • 一德路,玩具、文具、海味批发街。
  • 石室圣心大教堂,宏伟且独具特色的教堂。
  • 清平路,宠物交易市场。
  • 广州文化公园,沙面附近,里面有个十三行博物馆。
  • 沙面岛,西方历史建筑群,适合拍照打卡。

3.3. 广州塔

地铁站[广州塔] -> 广州塔广场 -> APM线 -> 海心沙 -> 广州图书馆 -> 广东省博物馆

  • 广州塔,又名“小蛮腰”,广州地标建筑。顶部有很贵的摩天轮。一般不上去。
  • 广州塔广场,可以跟广州塔合影。
  • 海心沙,亚运会 2010 年在广州的开闭幕式主场馆,已改造成海心沙亚运公园。
  • APM 线,一段很短的地铁,采用透明玻璃的车头,是小朋友必争的位置。
  • 广州图书馆,特色建筑物。
  • 广东省博物馆,有 1:1 的恐龙骨复制品,包括一只 3 层楼高的长颈龙。参观需预约。

3.4. 广州大学城

地铁站[大学城北] -> 广州大学城 -> 广东科学馆 -> 岭南印象园

  • 广州大学城,有10所高校,适合省内小朋友参观立 flag。注:未知是否对外封闭。
  • 广东科学中心,很大,能逛一天,尽量避免暑假等小孩多的日子(排队浪费时间)。需购票。
  • 岭南印象园,岭南传统风格建筑群落。参观需购票。

3.5. 荔湾

地铁站[长寿路] -> 永庆坊 -> 李小龙祖居 -> 荔枝湾 -> 上下九

  • 永庆坊,特色建筑群,有个粤剧博物馆。
  • 李小龙祖居,没去过。
  • 荔枝湾,广州著名河流。
  • 上下九,商业步行街。

3.6. 大型公园

地铁站[大塘] -> 广州海珠国家湿地公园 -> 广州文化馆新馆

  • 广州海珠国家湿地公园,大型公园,据说南门有10亩樱花,花期在3月。海珠湖免费预约,湿地公园需购票。
  • 广州文化馆新馆,大型特色建筑群,主要是唐朝风格,最好穿古装拍照。需免费预约。

3.7. 动物园

介绍几个动物园相关景点。

  • 长隆野生动物世界

    • 1997 年开幕时叫“香江野生动物世界”,当时已经很震撼。现在,个人认为除了人多,没有其它缺点。
  • 广州动物园

    • 门票便宜是最大优点。未去过,未能提供参考意见。
  • 芳村花鸟鱼虫新世界

    • 大型的树木、花卉、宠物、造景市场。我觉得是,可以购买动物的动物园。

3.8. 其它

很多景点还没去过,欢迎补充路线或相关信息。

  • 白云山,广州著名的山。需购票进入。
  • 南越王博物院(王墓展区),岭南两千年的历史遗迹。成人门票10元。
  • O2Park,门口是哈利波特主题餐厅和咖啡厅,提供斗篷(15元/30分钟)和魔法棒(15元/30分钟)租赁。
  • 中山大学,广东省顶尖高校,目前封闭管理,只能门口打卡。
  • 太古仓码头,特色商业区,一般会提到日落很美。
  • 东山口,流行经典。

虽然MP3格式存在很多缺点,但是其通用性强、文件大小范围下保证一定的音质,所以存储的音乐文件还是使用MP3格式。

这里记录一下Ubuntu上的相关工具。

1. SoundConverter

获取到的音频文件,其格式可能是整盘录制成FLAC或APE,先转换成MP3格式,再切分。

2. Mp3splt

如果是整盘音频文件,一般会自带CUE文件,描述包含音轨的时间、名称等信息。音频文件转换成MP3后,需要改一下CUE文件里所指定的音频文件名,才能用Mp3splt执行切分。

参考命令格式:

mp3splt -c music.cue music.mp3

3. EasyTAG

用来修正MP3文件的Tag信息,包括内嵌图片。

公司的Web项目,处理图片延迟加载时,遇到一个图片预留占位的显示问题。记录一下相关解决方案。

1. 需求

本来要解决的问题是,图片“延迟加载”。然后图片未加载之前,需要预留占位,避免加载后撑大页面(主要是为了更好看吧)。

2. 解决方案

图片延迟加载,使用<img>loading="lazy"即可。现代浏览器,当前对其支持还不错。另外,最好不用使用CSS的background加载图片,因为没有很好(或者说简单)的延迟加载解决方案。

对于图片预留占位,主要根据界面设计的布局,选择不同的处理方法。比较麻烦的是,需要自适应浏览器窗口大小的情况。如下:

  • 已知图片宽高。可以随便整。
  • 图片框固定大小。使用CSS的object-fit获得最佳显示效果。
  • 固定列数的图片框自适应浏览器窗口。按浏览器窗口自动计算图片框的宽度。
  • 图片框宽度自适应。使用动态的正方形图片框。这是最终采用的方案。

2.1. 已知图片宽高

可以设置图片按比例缩放,或者按最长边等比例缩放。这个不用说了。

2.2. 图片框固定大小

例如图片框固定,宽为300px,高为300px。图片保持比例,并完整显示,使用CSS的object-fit:contain;。代码如下:

<div style="width:300px; height:300px;">
  <img src="..." style="width:100%; height:100%; object-fit:contain;" />
</div>

2.3. 固定列数的图片框自适应浏览器窗口

一般是列表中带图片的情况,可以使用CSS的单位vwvh

  • vw,浏览器窗口宽度的1%
  • vh,浏览器窗口高度的1%

关于CSS的长度单位,详见: - CSS:层叠样式表 | MDN

缺点:

  • 如果图片的宽高,不能根据屏幕的宽高计算出来,此方案不适用。
  • 如果图片宽高不能适应图片框的比例,也是使用object-fit:contain;按比例缩放。

以下示例,按4列显示,图片框是宽高都为窗口宽度24%的正方形:

<style>
body{margin:0; padding:0;}
.ItemList{width:100%; margin:0; padding: 0; list-style: none; display: flex; flex-wrap: wrap; justify-content: space-evenly;}
.ItemWrap{width:24%; margin:1vw 0 0; padding:0; display: block;}
.ItemWrap img{width:24vw; height:24vw; object-fit: contain;}
</style>
<ul class="ItemList">
  <li class="ItemWrap"><img src="..." loading="lazy" /></li>
  <li class="ItemWrap"><img src="..." loading="lazy" /></li>
  <li class="ItemWrap"><img src="..." loading="lazy" /></li>
  <li class="ItemWrap"><img src="..." loading="lazy" /></li>
  <li class="ItemWrap"><img src="..." loading="lazy" /></li>
  <li class="ItemWrap"><img src="..." loading="lazy" /></li>
  <li class="ItemWrap"><img src="..." loading="lazy" /></li>
  <li class="ItemWrap"><img src="..." loading="lazy" /></li>
</ul>

2.4. 图片框宽度自适应

动态宽高的正方形图片框,是比较折中和灵活的方案。可以不用知道图片宽高。图片框宽度动态计算,高度设为跟高度一致。示例如下:

<style>
body{margin:0; padding:0;}
.ItemList{width:100%; margin:0; padding:0; list-style:none; display:flex; flex-wrap:wrap; justify-content:space-evenly;}
.ItemWrap{width:24%; margin:1vw 0 0; padding:0; display:block; background-color:#c5a29c;}
.ImgWrap{width:100%; height:0; padding-bottom:100%; overflow:hidden; display:block; position:relative;}
.ImgWrap img{width:100%; height:100%; object-fit:contain; position: absolute;}
</style>
<ul class="ItemList">
  <li class="ItemWrap"><a class="ImgWrap"><img src="" loading="lazy"></a></li>
  <li class="ItemWrap"><a class="ImgWrap"><img src="" loading="lazy"></a></li>
  <li class="ItemWrap"><a class="ImgWrap"><img src="" loading="lazy"></a></li>
  <li class="ItemWrap"><a class="ImgWrap"><img src="" loading="lazy"></a></li>
  <li class="ItemWrap"><a class="ImgWrap"><img src="" loading="lazy"></a></li>
  <li class="ItemWrap"><a class="ImgWrap"><img src="" loading="lazy"></a></li>
  <li class="ItemWrap"><a class="ImgWrap"><img src="" loading="lazy"></a></li>
  <li class="ItemWrap"><a class="ImgWrap"><img src="" loading="lazy"></a></li>
</ul>

解析:

  • ul标签,使用灵活的flex样式显示列表。
  • li标签,决定列数。
  • a标签,作为图片框,限制图片显示的宽高。
  • a标签的height:0; padding-bottom:100%;,通过padding-bottom设置高度与宽度一致,是这个方案最巧妙的地方
  • a标签的overflow:hidden;,避免内嵌的图片溢出。
  • a标签的position:relative;,把宽高传给子级。
  • img标签,通过position: absolute;悬浮显示在图片框上面,其宽高获取了图片框(即父级)的宽高。

3. 后续问题

图片加载时,小图最好加载对应的缩略图。体积小,加载快,体验好。但是要考虑图片框大小,避免小图被拉大而导致模糊,降低用户观感。

1. 概述

由于历史原因,工作上,需要把Microsoft SQL Server指定数据库上定时更新的数据,同步到MySQL 8,大概一周一次。

解决方案有几个:

  • 1)采用现成的工具。

    • 但是,一时间没找到好的工具。
  • 2) 开发个程序,读取SQL Server的相关数据,再插入到MySQL。

    • 需要时间开发,且功能上具有针对性。
    • 作为长期使用的工具,这是最优的方案。
  • 3) 从SQL Server生成MySQL的insert语句,再到MySQL上执行。

    • 很多数据库管理工具都提供了数据迁移功能,例如:MySQL Workbench。
    • 如果数据结构不变,insert语句是稳定的,这方案也不错。
    • 要注意采用批量插入,提高导入性能。
  • 4) 从SQL Server导出格式化数据,例如CSV文件,再导入到MySQL。

    • 由于保存数据的CSV文件比较通用,相关的数据库管理工具都支持导入导出。
    • 但是要注意要处理数据格式、NULL数据等问题。

目前采用了第3个方案,CSV文件比较通用,也不用考虑怎么开发。但是偶尔会出现导入MySQL失败的问题,比如出现了NULL数据。后面应该会写个程序处理,直接生成insert语句。

2. SQL Server导入导出CSV

一般使用BCP命令。即Bulk Copy Program,是一个命令行工具,用于在SQL Server之间批量传输数据。由于微软推出了SQL Server for Linux,所以可以完全在Linux执行导入导出的操作。另外,微软提供了SQL Server for Linux的官方Docker镜像,比Windows上安装SQL Server Express更方便,非常适合开发测试使用(主要应付历史)。

官方介绍及参考文档如下:

2.1. BCP使用说明

直接运行bcp命令,会提示其用,如下:

> C:\Program Files (x86)\Microsoft SQL Server\Client SDK\ODBC\130\Tools\Binn\bcp.exe

用法: bcp {dbtable | query} {in | out | queryout | format} 数据文件
  [-m 最大错误数]             [-f 格式化文件]       [-e 错误文件]
  [-F 首行]                   [-L 末行]             [-b 批大小]
  [-n 本机类型]               [-c 字符类型]         [-w 宽字符类型]
  [-N 将非文本保持为本机类型] [-V 文件格式版本]     [-q 带引号的标识符]
  [-C 代码页说明符]           [-t 字段终止符]       [-r 行终止符]
  [-i 输入文件]               [-o 输出文件]         [-a 数据包大小]
  [-S 服务器名称]             [-U 用户名]           [-P 密码]
  [-T 可信连接]               [-v 版本]             [-R 允许使用区域设置]
  [-k 保留 Null 值]           [-E 保留标识值]
  [-h"加载提示"]              [-x 生成 xml 格式化文件]
  [-d 数据库名称]

2.2. BCP导出CSV文件

CMD批处理命令参考如下:

set CUR_PATH=%~dp0
set BCP="C:\Program Files (x86)\Microsoft SQL Server\Client SDK\ODBC\130\Tools\Binn\bcp.exe"
set BCP_PARAM=-S "IP,端口" -U "用户名" -P "密码" -d "数据库名" -t \t -b 1000 -c -C 65001 -k

rem 导出指定数据库表的数据
%BCP% 数据库名.dbo.表名 out %CUR_PATH%table_export.csv %BCP_PARAM%

rem 导出指定查询语句的数据
%BCP% "select查询语句" queryout %CUR_PATH%query_export.csv %BCP_PARAM%

参数说明:

  • -S 服务器名称,服务器IP与端口之间,使用英文逗号(即“,”)分隔。
  • -t 字段终止符,默认是Tab符号(即“/t”)。
  • -b 批大小,如果导出数据太多,需要分页操作,默认是1000。
  • -c 字符类型,设置导出文件的字符编码为UTF-8时,设置为“-c -C 65001”,要注意大小写。

要注意,导出的CSV文件不带字段名称。需要记录字段名称时,目前只能把字段名称插入到CSV文件的第一行,并且以数据行的分隔符号进行分隔。

2.3. BCP导入CSV文件

要先创建对应的表,才能执行导入。格式如下:

set BCP_PARAM=-S "IP,端口" -U "用户名" -P "密码" -d "数据库名" -t \t -b 1000 -c -C 65001 -k
bcp 数据库名.dbo.表名 in 数据文件.csv %BCP_PARAM%

2.4. SQL语句执行BCP命令

要注意,用户需要授权可执行xp_cmdshell的权限。官方详细说明如下:xp_cmdshell (Transact-SQL) - SQL Server | Microsoft Learn

格式如下:

exec master..xp_cmdshell 'bcp ...'

2.5. SQL Server的其它导入导出方案

3. MySQL导入导出CSV

3.1. 相关参考

参考文章:MySQL导出数据为CSV的方法

MySQL官方文档:

3.2. MySQL导入CSV

假如导入数据到数据表user_table,该表有字段id、name、remark,其中remark数据可能为NULL。

-- 导入CSV文件的SQL语句
load data infile '/var/lib/mysql-files/import_data.csv' into table user_table fields terminated by '\t' escaped by '' optionally enclosed by '"' lines terminated by '\n' ignore 1 lines (id,name,@remark) set remark=nullif(@remark,'');

说明:

  • CSV文件需要放在mysql用户有权限的目录,比如/var/lib/mysql-files/
  • fields terminated by '\t',表示CSV数据以TAB符号分隔。
  • escaped by '',设置转义字符,默认的是反斜杠(backslash:\ ),设置空值('')表示不适用转义。
  • optionally enclosed by '"',以双引号包裹单一字段的数据。
  • lines terminated by '\n',每行数据的结束符号。
  • ignore 1 lines,导入数据时跳过第一行,因为第一行是字段名称的说明。
  • (id,name,@remark),把一行数据关联到对应的字段。其中@remark是把数据赋值到变量,后面有特殊处理。
  • remark=nullif(@remark,''),表示remark字段的数据,根据@remark变量进行处理。这里是NULL数据转为空字符串。

3.3. MySQL导出CSV

-- 导出CSV文件的SQL语句
select * from user_table into outfile '/tmp/expor_data.csv' fields terminated by '\t' escaped by '\\'  optionally enclosed by '"' lines terminated by '\n' ;

说明:

  • fields terminated by "\t",表示CSV数据以TAB符号分隔。
  • escaped by '\\',设置转义字符,默认的是反斜杠(backslash:\ ),设置空值('')表示不适用转义。
  • optionally enclosed by '"',以双引号包裹单一字段的数据。
  • lines terminated by '\n',每行数据的结束符号。

4. SQL语言的concat_ws函数

SQL的select语句可以使用concat_ws函数,可以实现一行数据的所有字段值合并成一个字符串,并指定分隔符号。然后把查询结果保存为文本文件(包括CSV),即实现了数据导出。参考文档如下:

Windows 11的任务栏,确实很鸡肋。于是想办法做功能增强。

1. 存在问题

对比历史版本Windows(XP、7、10)的任务栏,Windows 11任务栏存在以下缺点:

  • 可自定义功能不多
  • 不支持任务平铺,即不进行分组合并显示(注,2023-11-20,发现Win11更新后可以设置任务栏图标不合并)
  • 不能添加快捷菜单集合
  • 不能调整高度,占据屏幕空间比较多

2. 可选方案

2.1. ExplorerPatcher

2.2. StartAllBack

2.3. CLaunch

  • 项目地址:CLaunch
  • 优点:免费,轻量,对系统没有任何影响。
  • 缺点:只是个弹出菜单(不能替代任务栏),不开源。

3. 解决方案

最后,我选择了基于CLaunch,实现任务栏辅助。主要是解耦,避免对系统的影响,也便于维护、迁移和备份。

3.1. 任务栏设置

任务栏设置为自动隐藏,节省屏幕空间。

注:由于任务栏可以设置图标不合并,没必要隐藏任务栏了。

3.2. 部署CLaunch

其当前最新版v4.05,由于在virustotal.com被大量杀毒软件检测出木马,所以选择了v4.04。

皮肤推荐:yurafuca/claunch-win10: Windows 10 Flavored CLaunch Skin.

我比较喜欢只有一列的布局(像《刀剑神域》游戏里的菜单),并且设置显示规则为:

  • 双击屏幕左侧边缘显示
  • 双击桌面显示
  • 快捷键 Ctrl + Shift + Q 显示
  • 任务栏添加固定图标,点击即可显示

3.3. 常用快捷方式

常用的快捷方式,会保存到指定文件夹,在CLaunch指向该文件夹,并以子菜单显示。这样维护、备份、迁移都比较简单。

3.4. 平铺显示任务列表

Windows 11自动一个平铺任务列表,按 Win + Tab 显示。可以编写vbs文件,并在Claunch设置为按钮,现实点击显示。相关代码如下:

rem 文件名:tasks.vbs
rem 运行平铺显示的任务列表,Windows默认快捷键:Win + Tab
rem 参考:https://learn.microsoft.com/en-us/windows/win32/shell/shell-windowswitcher
set objShell = CreateObject("shell.application")
objShell.WindowSwitcher
set objShell = nothing

3.5. 添加快捷功能

比如要在Claunch添加按钮,实现显示桌面,可以使用vbs模拟按键实现。相关代码如下:

rem 文件名:desktop.vbs
rem 显示桌面,Windows默认快捷键:Win + D
rem 参考:https://learn.microsoft.com/en-us/windows/win32/shell/shell-toggledesktop
set objShell = CreateObject("shell.application")
objShell.ToggleDesktop
set objShell = nothing

关于vbs模拟按键,可以参考:VBS自动按键大全,vbs基本和特殊按键 - 笨蛋敏 - 博客园

例如要实现显示Windows开始菜单,可以使用Ctrl + ESC,模拟Win按键。相关代码如下:

rem 文件名:start.vbs
rem 显示开始菜单,Windows默认快捷键:Win
Set wsShell = WScript.CreateObject("WScript.Shell")
wsShell.SendKeys "^{ESC}"
set wsShell = nothing

3.6. 通讯软件的消息提醒

通讯软件有消息时,任务栏有提醒效果。如果任务栏自动隐藏,收到消息时会自动显示。如果觉得还不够,可能会导致错过消息,可以设置通讯软件(例如TIM),收到新消息就弹出对话窗口。

3.7. 显示时间

目前没有很好的解决方案。要么就装个显示时间的软件(例如 DesktopClock),要么就弹窗显示当前时间(代码如下)。但是两个方案都不够好用。

rem 文件名:show_time.vbs
rem 弹出当前日期时间
rem 注意:本VBScript文件涉及中文显示,需要使用ANSI编码
rem
rem 参考:
rem https://learn.microsoft.com/en-us/windows/win32/shell/shell-windows

rem 弹窗标题
title = "当前时间"
rem 弹窗保持的秒数,指定时间之后自动关闭。0为不自动关闭。
holdSec = 3

curDateTime = Now()
weekdayInt = Weekday(curDateTime)
Select Case weekdayInt
  Case 1
    weekdayStr="星期日"
  Case 2
    weekdayStr="星期一"
  Case 3
    weekdayStr="星期二"
  Case 4
    weekdayStr="星期三"
  Case 5
    weekdayStr="星期四"
  Case 6
    weekdayStr="星期五"
  Case 7
    weekdayStr="星期六"
  Case Else
    weekdayStr="星期日"
End Select

msg = Year(curDateTime) & "-" & Right("0" & Month(curDateTime), 2) & "-" & Right("0" & Day(curDateTime), 2) 
msg = msg & vbCrLf & Right("0" & Hour(curDateTime), 2) & ":" & Right("0" & Minute(curDateTime), 2) & ":" & Right("0" & Second(curDateTime), 2)
msg = msg & vbCrLf & weekdayStr

rem CreateObject("Wscript.Shell").Popup msg, 3, title, 64
Set objShell = CreateObject("WScript.Shell")
objShell.Popup msg, holdSec, title, 64
Set objShell = nothing

上个月,发现“cloudflare.com”被解析为“127.0.0.1”,于是研究了一下DNS污染。

1. 检测

可以直接使用相关网站,检查各个DNS针对指定域名的解析是否正确。例如:

也可以使用命令或工具,查询使用指定DNS解析指定域名的结果。nslookup命令的示例如下:

# nslookup 域名 DNS地址
nslookup cloudflare.com 223.5.5.5

2. 解决方案

一般设置DNS为可靠的共用DNS即可。由于是网络运营商的DNS发现的污染,所以不推荐使用三大运营商的DNS。暂时改为使用“阿里公共DNS”。

最简单的是,修改网络出口设备(例如路由器)的DNS,所有网络设备(例如手机、电脑)都使用其默认DNS。比较麻烦的是,各个网络设备各自设置DNS。

国内外的免费公共DNS,可参考:

几个比较有名的DNS如下:

3. 扩展内容

3.1. 关于nslookup命令

一般各大系统都有nslookup命令。对于Debian 11和Ubuntu 22.04,可能没有默认安装nslookup,需要手动安装。

# Debian或Ubuntu,安装nslookup命令
sudo apt install bind9-dnsutils

# 查看域名的DNS A记录解析
nslookup -type=A cloudflare.com 223.5.5.5

该命令的详细说明,可以参考man nslookup或Debian官方文档:nslookup(1) — bind9-dnsutils — Debian bookworm — Debian Manpages

3.2. 如何修改DNS配置

3.2.1. 总结

  • 路由器,进入其管理后台,修改DNS配置。
  • 网络终端设备(电脑,手机等),需要明确配置DNS的范围,一般是:全局、指定网络接口、指定代理服务。
  • 全局DNS,需确定管理DNS服务的程序,再修改其配置文件。
  • 指定网络接口的DNS,一般修改其网卡设置。
  • 代理服务的DNS,一般不走本地设置,需要参考该代理服务的配置说明。

3.2.2. 关于配置全局DNS

对于Linux(例如Debian 12),一般查看/etc/resolv.conf文件,可以了解当前使用什么DNS。直接修改该文件,可以更改当前全局DNS,例如:

# 设置DNS为阿里DNS
nameserver 223.5.5.5

但是,如果有其它程序接管了/etc/resolv.conf文件,比如systemd-resolved服务,系统重启后会该文件被重置,导致设置无效。注意各个系统的情况不同,比如:

  • Debian 11/12,默认没有安装systemd-resolved
  • Ubuntu 22.04,默认安装并启用systemd-resolved

3.2.3. 关于配置网络接口DNS

  • 图形界面,通过网络配置,修改相应的DNS。

    • 例如Ubuntu 22.04,使用NetworkManager管理。网络接口的配置文件在/etc/NetworkManager/system-connections/
  • 命令界面,一般修改配置文件/etc/network/interfaces

    • 例如Debian 11/12,其示例配置如下:
# This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).

source /etc/network/interfaces.d/*

# The loopback network interface
auto lo
iface lo inet loopback

# The primary network interface
allow-hotplug enp3s0
#iface enp3s0 inet dhcp
iface enp3s0 inet static
    address 192.168.0.100
    netmask 255.255.255.0
    gateway 192.168.0.1
    dns-nameservers 223.5.5.5 192.168.0.1

3.3. 管理DNS缓存

3.3.1. Linux的DNS缓存

  1. 使用systemd-resolve,适合Ubuntu 20.04及以下、Debian 11/12等。
# 清除DNS缓存
sudo systemd-resolve --flush-caches

# 查看DNS缓存情况
sudo systemd-resolve --statistics

对于Debian 11/12,需要启用systemd-resolve服务。

sudo systemctl enable systemd-resolved.service
  1. 使用resolvectl,适合Ubuntu 20.04以上。
# 清除DNS缓存
sudo resolvectl flush-caches

# 查看DNS缓存情况
sudo resolvectl statistics
  1. 重启网络服务,清除DNS缓存,适合一般Linux。
# 基于Init.d的系统
sudo /etc/init.d/networking restart

# 基于SystemD的系统
sudo service networking restart

3.3.2. Windows的DNS缓存

rem 清除DNS缓存
ipconfig /flushdns

3.3.3. Chrome浏览器的DNS缓存

Chrome本身建立了自己的DNS缓存,并提供简单的管理功能。打开链接:chrome://net-internals/#dns 即可。

利用Nginx部署了图片服务,为了实现请求图片时进行鉴权,使用了auth_request的配置。

参考官网文档:Authentication Based on Subrequest Result | NGINX Documentation

整理后的示例代码,如下:

server {
    ...... # 略过一些配置
    underscores_in_headers on; # 可选。允许请求header名称带下划线(_)

    location ^~ /images/ {
        # 配置鉴权规则
        auth_request /auth;

        # 生成鉴权URL,并添加请求参数。
        set $auth_request_uri $uri; # 创建变量,传递鉴权URL
        if ($uri ~ ^/images/(.*)$) {
            # 利用if实现对URL进行字符串替换,生成想要的鉴权URL,并带上请求参数
            # 由于静态文件,尤其是图片,一般使用GET方法,所以URL的请求参数可以作为鉴权参数
            set $auth_request_uri /auth/$1?$args;
        }

        # 将401、403状态码映射为404。即鉴权失败时,让浏览器以为文件不存在。
        # 由于“/404.html”不存在,Nginx会返回默认的404错误页面。
        error_page 401 403 =404 /404.html;

        # 设置图片存放目录,/images/有/结尾,这里也要有/结尾
        alias /opt/sites/pub_img/;
    }

    # 这里配置鉴权后端的请求,即鉴权URL
    location = /auth {
        internal; # 只能内部访问
        proxy_pass http://127.0.0.1:8080$auth_request_uri; # 设置完整的鉴权URL
        proxy_pass_request_headers on; # 默认值。转发所有原始的请求header到鉴权URL
        proxy_pass_request_body off; # 不向鉴权URL接发送原始的请求体
        proxy_set_header Content-Length ""; # 不向鉴权URL发送原始的请求体
        proxy_set_header X-Original-URI $request_uri; # 传递原始的请求URL
    }
}

说明和总结

  1. 此方式能轻松实现静态文件进行灵活的鉴权,甚至是无权限服务添加访问权限。

    • Nginx支持的鉴权配置,有4种:
  2. 使用鉴权URL时,基本目前基于请求头和URL参数的鉴权方式都支持,非常灵活。

    • proxy_pass_request_headers默认为on,会把原始请求Header转发到鉴权URL
    • 生成鉴权URL时,会把原始URL参数传过去。
  3. 鉴权URL的处理,最好跟原始URL无关,并把原始URL作为鉴权参数传过去。本示例代码做了URL字符串替换,对后面扩展不够灵活。
  4. 不建议使用Nginx实现复杂的功能。其配置文件不是代码,不是按顺序执行,也不方便调试。

记录一下今天Lubuntu 22.04.2的桌面环境(LXQt 1.2.0)罢工,以及解决办法。

问题

今天打开电脑,直接进入tty1的字符界面(明明昨晚还是好好的)。登录后执行startlxqt,显示以下提示:

qt.qpa.xcb: could not connect to display
qt.qpa.plugin: Could not load the Qt platform plugin "xcb" in "" even though it was found.
This application failed to start because no Qt platform plugin could be initialized. Reinstalling the application may fix this problem.

Available platform plugins are: eglfs, linuxfb, minimal, offscreen, vnc, xcb.

Aborted

就是LXQt不能启动,导致不能进入图形界面环境。

解决

找了几个文章都没有解决。直到看了这个:

[SOLVED]cinnamon doesn't start because of segfault in libgtk-3.so.0.2404.27

该文章提到SDDM。于是执行了安装SSDM命令sudo apt install sddm,重启后就解决了。

总结

  1. 好久没有体验过Linux图形界面的脆弱了。
  2. 这个错误被提及很多,但是涉及的问题各有不同。是Qt5的锅吗?
  3. 习惯了日常升级系统,想不到Lubuntu也踩坑。