0%

记录我的联想M720Q Arch Sway窗口管理器的安装和配置过程

安装Arch Linux基本过程纪录

下载并烧录镜像

本次下载2021.5.1日的镜像,写这篇文章的时候是六一儿童节,但是并没有看到这个月的镜像。好耶,都去过六一了!

应该是最后一次用东软维云的镜像站咯!下载Arch 2021.5.1 ISO走起。

引导系统

引导Arch ISO前在BIOS中关闭安全引导,借着还有Windows的时候,更新了一下BIOS到2021年三月份的版本。

链接到互联网

在 Arch ISO Live中安装了iwd来管理无线网络,因为本次安装过程只有无线网络,那么用iwctl工具来配置本次安装过程中使用的无线网络。

进入iwctl交互模式: iwctl

罗列设备: device list,在列表中可以找到wlan0无线设备,记下来他的名字,接下来会使用到这个名称。

扫描无线网络: station wlan0 scan

罗列已发现的网络 station wlan0 get-networks

连接到无线网络 station wlan0 connect SSID

删除多余的引导

使用efibootmgr删除Windows引导。

efibootmgr -b 000X -B

更新系统时间

使用timedatectl更新时间,开启ntp。确保系统时间是准确的: timedatectl set-ntp true

建立硬盘分区

使用fdisk工具对磁盘进行分区,我要将整个磁盘都空间都划分给Arch使用。

fdisk /dev/nvme0n1

  • ESP分区 1G
  • SWAP分区 8G
  • 根文件存储 剩余空间

格式化磁盘文件系统

将ESP被格式化成,ESP分区格式化成FAT32分区格式: mkfs.vfat -F32 /dev/nvme0n1p1

创建SWAP文件系统:

mkswap /dev/nvme0n1p2

swapon /dev/nvme0n1p2

创建根目录文件系统ext4: mkfs.ext4 /dev/nvme0n1p3

挂载分区

挂载根分区目录: mount /dev/nvme0n1p3 /mnt

创建EFI目录并进行挂载:

mkdir /mnt/efi

mount /dev/nvme0n1p1 /mnt/efi

选择镜像源

文件 /etc/pacman.d/mirrorlist 定义了软件包会从哪个镜像源下载。在 LiveCD 启动的系统上,在连接到因特网后,reflector 会通过选择 20 个最新同步的 HTTPS 镜像并按下载速率对其进行排序来更新镜像列表。

在列表中越前的镜像在下载软件包时有越高的优先权。您或许想检查一下文件,看看是否满意。如果不满意,可以相应的修改 /etc/pacman.d/mirrorlist 文件,并将地理位置最近的镜像源挪到文件的头部,同时也应该考虑一些其他标准。

这个文件接下来还会被 pacstrap 拷贝到新系统里,所以请确保设置正确。

安装系统软件包

pacstrap /mnt base linux linux-firmware base-devel networkmanager

写入引导

用以下命令生成 fstab 文件 (用 -U 或 -L 选项设置UUID 或卷标):

genfstab -U /mnt >> /mnt/etc/fstab

强烈建议在执行完以上命令后,后检查一下生成的 /mnt/etc/fstab 文件是否正确。

切换根目录

Chroot更当前进程及其子进程的可见根路径。变更后,程序无法访问可见根目录外文件和命令。

arch-chroot /mnt

安装一些常用软件包

pacman -S vim bash-completion

设置时区时间

timedatectl set-timezone Asia/Shanghai

hwclock --systohc

设置使用的区域

编辑/etc/locale.gen然后移除需要的 地区 前的注释符号 #

接着执行 locale-gen 以生成 locale 信息

编辑/etc/locate.conf:

LANG=en_US.UTF-8

设置全局区域环境为美国英语环境。

稍后用户可以编辑自己的~/.config/locale.conf文件来设置使用的语言和特定的区域格式。如:

  • LANG
  • LANGUAGE
  • LC_ADDRESS
  • LC_COLLATE
  • LC_CTYPE
  • LC_IDENTIFICATION
  • LC_MEASUREMENT
  • LC_MESSAGES
  • LC_MONETARY
  • LC_NAME
  • LC_NUMERIC
  • LC_PAPER
  • LC_TELEPHONE
  • LC_TIME

LANG:默认的区域设置
这个变量的值会覆盖掉所有未设置的 LC_* 变量的值。

相关详情访问: Arch Wiki - Locate(简体中文)

设置主机名

hostnamectl set-hostname Archxxxxxx

设置用户及ROOT密码

设置root用户密码: passwd

添加普通用户并设置密码:

useradd -m username

passwd username

将用户添加到管理员组(wheel): usermod -aG wheel username

编辑/etc/sudoers文件允许wheel组中用户使用sudo提权到root级别权限。

安装引导程序

安装引导是安装的最后一步,使用GRUB配置本机引导,首先安装grubefibootmgr两个包。

pacman -S grub efibootmgr

然后按照下列步骤安装 GRUB:

挂载 EFI 系统分区,在本节之后的内容里,挂载点为/efi

选择一个启动引导器标识,这里叫做 GRUB。这将在 esp/EFI/ 中创建一个与标识同名的目录来储存 EFI 二进制文件,而且这个名字还会在 UEFI 启动菜单中表示 GRUB 启动项。

执行下面的命令来将 GRUB EFI 应用 grubx64.efi 安装到 esp/EFI/GRUB/,并将其模块安装到 /boot/grub/x86_64-efi/。

grub-install --target=x86_64-efi --efi-directory=/efi --bootloader-id=GRUB

生成GRUB配置文件: grub-mkconfig -o /boot/grub/grub.cfg

安装后的一些系统服务配置

使用NetworkManager管理本机网络

刚才在安装过程中使用pacstrap安装软件包时就已经将networkmanager软件包安装好了,接下来开启NetworkManager服务,并使用nmcli配置连接无线网络。

systemctl enable --now NetworkManager

罗列当前可用的无线网络: nmcli device wifi list

连接到SSID_NAME无线网络
nmcli device wifi connect SSID_NAME ifname wlp3s0 password <mypassword> name XXXXX

若要交互式的输入密码,可以加-a --ask参数,避免在终端内输入密码留下痕迹。

nmcli device wifi connect SSID_NAME ifname wlp3s0 name XXXXX

此时缺省password参数,会在终端内进行交互式输入密码。

PPPoE / DSL support

若要使用PPPoE拨号,需要rp-pppoe软件包后,才可以用nmcli连接。

pacman -S rp-pppoe

nmcli connection add type pppoe pppoe.username "myusername" pppoe.password "mypassword" ifname "enp1s0f1" con-name "NDR" autoconnect yes

nmcli connection up NDR

配置EAP PEAP认证无线网络

校内的无线网络使用EAP认证,通过查阅资料使用nmcli添加EAP无线网络方法如下:

nmcli connection add type wifi con-name my-CUCC ifname wlp3s0 ssid CUCC ipv4.method auto 802-1x.eap peap 802-1x.phase2-auth mschapv2 802-1x.identity yourusername 802-1x.password yourpassword wifi-sec.key-mgmt wpa-eap autoconnect yes

桌面窗口服务

使用Wayland图形显示服务,sway平铺窗口管理器。

常见的环境配置文件所在地址

对于特定用户,还可以在 /.bashrc、/.xinitrc 或 ~/.xprofile 中设置自己的用户环境。不同之处在于:

.bashrc:每次使用终端登录时读取并运用里面的设置。

.xinitrc:每次使用 startx 或 SLiM 启动 X 界面时读取并运用里面的设置。

.xprofile:每次使用 GDM 等显示管理器登录时读取并运用里面的设置。

安装wayland和Sway以及依赖的一些包

pacman -S wayland sway

pacman -S alacritty swayidle

有关使用Wayland中的常见问题详见Arch Wiki - Wayland

配置Sway平铺窗口管理器

配置在登录系统后自动启动sway,以及配置Sway的程序启动器,任务栏,和各种优化。

配置tty登录后自动运行sway

vim ~/.bash_profile

启动Sway时,设置环境变量,其中包含让firefox使用wayland的标记变量以及QT环境等变量信息。

vim ~/.local/bin/sway

#!bin/sh
set -a
[ -f $HOME/.config/sway/env ] && . "$HOME/.config/sway/env"
set +a

if [ -z $DISPLAY ] && [ "$(tty)" = "/dev/tty1" ]; then
exec sway
fi

编辑环境变量文件:

MOZ_ENABLE_WAYLAND=1
QT_QPA_PLATFORM=wayland
  • MOZ_ENABLE_WAYLAND=1 : 火狐浏览器使用Wayland图形窗口服务标记
  • QT_QPA_PLATFORM=wayland : 在Wayland环境下使用Qt5需要安装qt5-wayland包,并设置QT_QPA_PLATFORM=wayland环境变量。

使用wofi作为程序启动坞

安装wofi: yay -S wofi

修改Sway配置文件

set $menu dmenu_path | wofi --show drun -i | xargs swaymsg exec --

rofi-emoji

使用dex自动启动程序-Fcitx5(自启动fcitx5)

fcitx5等一些应用会创建XDG Autostart启动配置,通常以.desktop文件拓展名结尾。像fcitx5等一些程序包在安装时会在/etc/xdg/目录下生成配置文件,但是只有部分的窗口管理器支持xdg启动。在Sway中目前没有看到原生对它的支持,所以就需要一些其它工具辅助执行。

那么若要在进入桌面环境后自动启动fcitx5,则可以使用dex工具。它可以自动执行/etc/xdg/autostart目录下的.desktop程序启动配置文件。

安装dex: yay -S dex

在Sway配置文件中配置自启动dex:

~/.config/sway/config 文件末尾处添加: exec_always "dex -a"

之后在Sway启动后,会执行dex工具,dex工具又回去执行哪些在XDG自动启动目录下,但是在Sway中不会自动执行的程序启动配置文件.desktop,此时fcitx5已经可以自动启动了。

安装中文字体

推荐安装以下常用开源中文字体:

  • wqy-microhei
  • wqy-microhei-lite
  • wqy-bitmapfont
  • wqy-zenhei
  • noto-fonts-cjk

yay -S wqy-microhei wqy-microhei-lite wqy-bitmapfont wqy-zenhei noto-fonts-cjk

更新字体缓存: fc-cache -fv

关于更多本土化中文字体设置详见

Arch Wiki Simplified Chinese

锁屏工具swaylock

我使用的是swaylock-effects

创建锁屏执行脚本文件: sudo vim /usr/bin/lock-screen

#!/bin/bash
#
swaylock --screenshots --clock --indicator --indicator-radius 100 \
--indicator-thickness 7 --effect-blur 7x5 --effect-vignette 0.5:0.5 \
--ring-color bb00cc --key-hl-color 880033 --line-color 00000000 \
--inside-color 00000088 --separator-color 00000000 --grace 2 --fade-in 0.2

赋予全体用户执行权限: chmod u+x /usr/bin/lock-screen

接下里配置Sway配置文件: vim .config/sway/config

### Idle configuration
#
# Example configuration:
#
exec swayidle -w \
timeout 300 'lock-screen &' \
timeout 500 'swaymsg "output * dpms off"' \
resume 'swaymsg "output * dpms on"' \
before-sleep 'lock-screen &'
# This will lock your screen after 300 seconds of inactivity, then turn off
# your displays after another 200 seconds, and turn your screens back on when
# resumed. It will also lock your screen before your computer goes to sleep.

上面的部分配置为Sway默认配置,简单修改为上面的配置即可,修改好配置文件好需要重启Sway后才可以生效,因为使用的是exec,所以重新加载配置文件还不能生效,如果想要查看效果。可以: killall -9 sway ,之后重新登录系统等待查看效果。

延时工具swayidle配置

swayidle我用来和swaylock-effects搭配使用,用于在一定时间内无操作后自动执行脚本或程序,所以可以用来解决一定时间哪无操作自动锁屏的需求。

zsh

安装zsh: yay -S zsh

更改用户默认Shell: usermod --shell /usr/bin/zsh username

要注意bash_profile等文件是否有内容,如果有的话需要迁移为zsh相关的文件。

初始化默认配置文件:

git clone git://github.com/robbyrussell/oh-my-zsh.git ~/.oh-my-zsh
cp ~/.oh-my-zsh/templates/zshrc.zsh-template ~/.zshrc
source .zshrc

常用软件包

这里会记录一些我常用的软件包

  • git
  • vim
  • bash-completion bash自动补全
  • rp-pppoe 对PPPoE的支持
  • openssh openssh 需要开启服务
  • rclone 挂载云盘
  • yay 使用yay管理AUR源
  • proxychains-ng 终端代理,可配置代理链
  • v2ray-core 请珍惜眼前所拥有的一切
  • ntfs-3g 挂载ntfs设备
  • qt5-wayland 在Wayland下支持Qt5,需要配置环境变量

开启archlinuxcn

我使用清华大学archlinuxcn源

使用方法:

/etc/pacman.conf 文件末尾添加以下两行,并安装 archlinuxcn-keyring 包导入 GPG key。

[archlinuxcn]
Server = https://mirrors.tuna.tsinghua.edu.cn/archlinuxcn/$arch

安装fcitx5-rime中文输入法

安装以下包:yay -S fcitx5 fcitx5-qt fcitx5-gtk fcitx5-configtool fcitx5-rime qt5-wayland

若在Wayland环境下使用Qt5需要安装qt5-wayland包,并设置QT_QPA_PLATFORM=wayland环境变量

yay安装

git clone https://aur.archlinux.org/yay.git
cd yay
makepkg -si

或者在开启了archlinuxcn源后直接通过源安装。

pacman -S yay

让yay通过proxychains使用代理

go版本的yay不能使用proxychains进行代理,所以需要替换安装以下的软件包:

yay -S gcc-go (代替go)
yay -S yay (or yay-git)

重新安装yay后还需要更改proxychains的配置文件:将52行附近的proxy_dns前使用#注释#proxy_dns

Edge浏览器

从AUR源中安装微软Edge浏览器: yay -S microsoft-edge-dev-bin

在Wayland环境下,还需要对Edge浏览器的启动脚本做些手脚才能正式使用。

vim /usr/bin/microsoft-edge-dev

在exec指令中添加两个参数:

-enable-features=UseOzonePlatform

-ozone-platform=wayland

目前没办法在EDGE浏览器中使用输入法,待解决

安装Wine

Wine目前原生不支持wayland,需要Xwayland支持。不过经过搜索后发现Wine的Git仓库中存在了wayland分支,并且在持续开发,截止到目前已经支持wayland环境与Wine运行的应用共享剪贴板。

接下来尝试使用wayland的分支尝试编译运行。

emmmm失败了,错误提示找不到显示驱动,先不折腾它,接下来试试Xwayland吧。

安装Xwayland

yay -S xorg-xwayland

安装wine

Wine可通过开启Multilib仓库来安装wine包及依赖。

vim /etc/pacman.conf

[multilib]
Include = /etc/pacman.d/mirrorlist

yay -Sy

yay -S insatll wine

Jenkins Linux 安装

在官网下载Jenkins

下载当前最新的稳定版Jenkins保存到指定目录。

安装包下载

wget -O ./jenkins.war http://mirrors.jenkins.io/war-stable/latest/jenkins.war

配置Jenkins的JAVA运行环境

Kenkins需要Java虚拟机才可以运行,在运行Jenkins前先配置JAVA虚拟机环境。

下载 Java JRE Linux X64

Java JRE安装包下载

wget -O ./jre-8u281-linux-x64.tar https://javadl.oracle.com/webapps/download/AutoDL?BundleId=244058_89d678f2be164786b292527658ca1605

安装Java JRE

将下载好的Java JRE安装包移动你要安装的目录里,我想要安装在/usr/java目录下。

(ROOT)创建安装目录sudo mkdir -p /usr/java

(ROOT)移动安装包sudo mv ./jre-8u281-linux-x64.tar /usr/java

(ROOT)解压 sudo tar -zxvf /usr/java/jre-8u281-linux-x64.tar

查看/usr/java目录你会发现除了安装包外新存在一个名字与jre1.8.0_281差不多相同的目录(这取决于你下载的JavaJRE版本)

那么现在你的Java JRE安装在了/usr/java/jre1.8.0_281内,现在可以将/usr/java/目录下的Java JRE安装包删除掉以节省空间

接下来配置环境变量,请根据自己Linux发行版的规则变通的配置/etc/profile

/etc/profile文件开始处填写:

export JAVA_HOME=/usr/java/jre1.8.0_281/
export JRE_HOME=/usr/java/jre1.8.0_281/
export CLASS_PATH=.:$JAVA_HOME/lib/rt.jar:$JRE_HOME/lib
export JAVA_PATH=$JAVA_HOME/bin:$JRE_HOME/bin

之后找到PATH,在PATH末尾填写上${JAVA_PATH}。请根据自己的实际情况填写,否则可能会覆盖之前的环境变量哦!

我的环境变量配置如下:

export JAVA_HOME=/usr/java/jre1.8.0_281/
export JRE_HOME=/usr/java/jre1.8.0_281/
export CLASS_PATH=.:$JAVA_HOME/lib/rt.jar:$JRE_HOME/lib
export JAVA_PATH=$JAVA_HOME/bin:$JRE_HOME/bin

if [ "`id -u`" -eq 0 ]; then
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:${JAVA_PATH}"
else
PATH="/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games:${JAVA_PATH}"
fi
export PATH

激活环境变量 source /etc/profile

查看配置是否成功则执行java -version,出现版本信息则配置成功:

java version "1.8.0_281"
Java(TM) SE Runtime Environment (build 1.8.0_281-b09)
Java HotSpot(TM) 64-Bit Server VM (build 25.281-b09, mixed mode)

初始化Jenkins

准备工作已经结束,接下来开始进行初始化Jenkins!

回到下载Jenkins的目录,执行java -jar jenkins.war --httpPort=8080命令。这里的8080是Web界面的端口号,你可以修改成自己需要的端口号,注意防火墙要放行该TCP端口。

首次运行Jenkins,首次运行Jenkins时会在当前用户家目录下生成一些配置文件~/.jenkins

访问你的域名或IP地址加上端口号后,你可以看到这样的界面。

01-first-interface-2021-02-06-14-31-08

此时Jenkins会下载一些资源,需要等待5分钟左右。如果时间过长,结束掉现在运行的Jenkins,先需要更改国内下载源来加快速度:

cd ~/.jenkins
vim hudson.model.UpdateCenter.xml

# 将<url>标签内的网址改为清华源

# 将下面的内容
<url>https://updates.jenkins.io/update-center.json</url>
# 修改为

<url>https://mirrors.tuna.tsinghua.edu.cn/jenkins/updates/update-center.json</url>

之后回到Jenkins软件包的目录下重新执行java -jar jenkins.war --httpPort=8080

稍后页面会让你输入管理员密码解锁安装Jenkins。管理员密码可以在运行Jenkins的终端上找到,也可以根据页面提示的文件中找到。

Jenkins安装解锁密码

输入密码后下一步会安装基本常用插件,选择左侧的选项开始安装即可。

Jenkins安装常用插件

此时需要一段时间等待……

如果出现插件安装失败,不用担心,很可能是Jenkins版本不支持当前下载的最新插件,稍后进入到Jenkins管理页面更新Jenkins版本即可。

Jenkins安装插件部分插件安装失败

接下来根据你的个人需求配置管理员用户名密码等设置。

配置开机自动启动 systemd 守护进程

以下内容使用于以war包形式部署Jenkins的方式来配置systemd守护进程服务,其它方式安装的Jenkins需要你自己变通。

以下内容参考linux(centos8):用systemctl管理war包形式的jenkins(java 14 / jenkins 2.257)这篇文章。

创建管理脚本

vim jenkins-control.sh创建新文本文件,将以下内容写入到文件中。

#!/bin/bash
#

source /etc/profile

pid=`ps -ef | grep jenkins.war | grep -v 'grep'| awk '{print $2}'| wc -l`
if [ "$1" = "start" ];then
if [ $pid -gt 0 ];then
echo 'jenkins is running...'
else
nohup $JAVA_HOME/bin/java -jar /home/hackinsss/Jenkins/jenkins.war --enable-future-java --httpPort=8088 2>&1 &
fi
elif [ "$1" = "stop" ];then
exec ps -ef | grep jenkins | grep -v grep | awk '{print $2}'| xargs kill -9
echo 'jenkins is stop..'
else
echo "Please input like this:"./jenkins.sh start" or "./jenkins stop""
fi

为脚本文件赋予执行权限 chmod u+x jenkins-control.sh

启动Jenkins ./jenkins-control.sh start

关闭Jenkins ./jenkins-control.sh stop

上面两个操作没有问题,能正确开启或关闭Jenkins的话则脚本运行没有问题,开始编辑systemd服务文件。

创建systemd服务文件

sudo vim /etc/systemd/system/jenkins.service

修改运行Jenkins的用户和脚本路径地址为你自己的。不推荐使用root权限运行Jenkins

[Unit]
Description=Jenkins
After=network.target

[Service]
Type=forking
User=使用该用户运行Jenkins
Group=使用该用户组运行Jenkins
ExecStart=/home/hackinsss/Jenkins/jenkins-control.sh start
ExecReload=
ExecStop=/home/hackinsss/Jenkins/jenkins-control.sh stop
PrivateTmp=true

[Install]
WantedBy=multi-user.target

sudo systemctl daemon-reload

设置开机自动运行Jenkins sudo systemctl enable jenkins

运行Jenkins sudo systemctl start jenkins

停止运行Jenkins sudo systemctl start jenkins

安装Jenkins流程记录到此结束。

[腾讯课堂、钉钉]在线网课视频直播回放下载离线播放

有些精品好课真的是百看不厌、教师精心准备、学习氛围也好。不过有些已购买的课程却只能在线观看…现在讲究的是一个环保、节能。如果能将已购买的课程离线下载好,那么会为各大平台节省多少带宽费用当然还有数据包在这世间重复的传输所浪费的电力资源。

本着环保、节能、减排的目的,开始了尝试对腾讯课堂网页版中自己购买了课程的视频回放进行下载。

然后顺便又看了下钉钉的回放。

github直达项目:https://github.com/yeefire/cloud-class-replay

腾讯课堂

由于没有使用客户端,在网页上观看。使用浏览器中的开发者工具来寻找请求。

tencent_class_safari_devnet-2020-12-28-00-30-43

可以看到请求了很多视频片段,文件拓展名为ts,GET请求。于是直接复制求请求连接然后丢在浏览器地址栏播放,结果不行,是加密的。

因为看到了ts,那么八九不离十使用的是M3U文件存储分段多媒体信息。

ts是日本高清摄像机拍摄下进行的封装格式文件,全称为MPEG2-TS。

M3U8是Unicode版本的M3U,用UTF-8编码。”M3U”和”M3U8”文件都是苹果公司使用的HTTP Live Streaming格式的基础,这种格式可以在iPhone和Macbook等设备播放。

寻找M3U

在请求中搜索m3u,出现了几个m3u8拓展文件,选择资源文件最大的那个m3u8文件,获取cURL请求或者其他方式将其下载到本地方便进一步分析。

现在找到了m3u文件,我们可以获取到这节课的所有分段视频了。

tencent_class_safari_search_m3u8-2020-12-28-00-48-19

分析腾讯课堂M3U文件

已经下载好了m3u8拓展文件,接下来打开文件进行分析!

可以看到腾讯课堂的每个分段视频是使用AES-128进行加密的,好在下载到的m3u8文件里给出了解密密钥的地址以及偏移量。

这下我们有了密钥和偏移量还有分段视频的请求参数(还不知道HTTP请求路径)

tencent_class_m3u8_file-2020-12-28-01-06-24

tencent_class_m3u8_check-2020-12-28-01-11-59

整理总结

现在可以尝试下载一个小的视频片段,不过目前还没有请求视频片段的完整路径,只有一个个的请求参数。这个好办,再回到浏览器中播放回放视频,观察浏览器开发者工具中的网络请求动态,找到’vxxxxxx.ts’请求,并查看获取该视频片段的完整HTTP请求路径。

发现和m3u8的请求路径与其相似。

m3u: https://xxxxxxxxxx.vod2.myqcloud.com/xxxxxxxxxxxxxx/b4e0xxxxxxxxxxxxxx7/drm/voddrm.xxxxxxxxxxxxx

ts: https://xxxxxxxxxx.vod2.myqcloud.com/xxxxxxxxxxxxxx/b4e0xxxxxxxxxxxxxx7/drm/v.fxxxx.ts?start=195027344&end=195666559&type=mpegtsxxxxxxxxxxxxx

在最后出现/斜杠位置前的所有请求路径都相同。并且斜杠后的请求参数正是m3u文件中的一个个分段视频的请求参数,看来仅仅需要简单的拼接就可以将这些分段视频下载好了。

那么现在我们有了全部分段视频的下载请求地址、解密算法、解密密钥及偏移量。有了这些就可以尝试下载分段视频并进行解密和合并了。

先尝试解密一个分段视频试试看:

with aiofiles.open(m3u8_encrypt_file, mode='rb') as f:
f = f.read()
content_video_part = AES.new(key, AES.MODE_CBC, iv).decrypt(f)
with aiofiles.open(dest_decrypt_file, mode='wb') as f:
f.write(content_video_part)

可以正常播放,没有问题。接下来下载全部的分段视频并解密,最后重新整合为一个mp4格式视频文件。剩下的交给脚本处理了!

腾讯课堂回放下载脚本

脚本使用异步进行请求下载分段视频和解密视频,尽可能的以最快的速度下载好全部的分段视频。

如果下载期间遇到网络波动,脚本可以自动重试下载。

若脚本意外停止,可以继续追加下载,不必全部重新开始下载分段视频。

使用方法:

  • 先安装依赖模块 pip3 install pycrypto m3u8 aiofiles requests_async
  • 命令行执行 python3 tencent_class_m3u8.py 这节课的名称 这节课的M3U文件请求地址(网址或者本地路径都可以)

例如: python3 tencent_class_m3u8.py 【Python进阶】Python-上午 https://1dada217.vod2.myqcloud.com/fdadadada3kmdkfsxxxxxxxxxxxxxxxxx

from Crypto.Cipher import AES
import requests_async as requests
import aiofiles
import m3u8
import os, sys
import asyncio

class_video_name = sys.argv[1]
m3u8_file_uri = sys.argv[2]
prefix_request_url = f'{m3u8_file_uri.rsplit("/", 1)[0]}/'


async def download_m3u8_video(index: int, suffix_url: str):
if not os.path.exists(f'{class_video_name}/downloads/{index}.ts'):
i = 0
while i < 3:
try:
download_video_ts = await requests.get(url=prefix_request_url + suffix_url, timeout=30)
with open(f'{class_video_name}/downloads/{index}.ts', "wb") as ts:
ts.write(download_video_ts.content)
print(f'[{class_video_name}]——已下载第 {index} 个片段/ 共 {len(playlist.files)} 个片段')
return
except requests.exceptions.RequestException:
print(f'[{class_video_name}]——下载超时,正在重新下载第 {index} 个片段/ 共 {len(playlist.files)} 个片段')
await asyncio.sleep(i)
i += 1


async def download_m3u8_all():
if not os.path.exists(class_video_name + '/downloads'):
os.makedirs(class_video_name + '/downloads')
download_async_list = [asyncio.create_task(download_m3u8_video(i, video_suffix_url))
for i, video_suffix_url in enumerate(playlist.files, 1)]
await asyncio.wait(download_async_list)

download_encrypt_list = [uri for uri in os.listdir(f'{class_video_name}/downloads') if uri[0] != '.']
if len(download_encrypt_list) == len(playlist.files): # 判断是否有漏下的分段视频没有下载
print(f'[{class_video_name}]——视频全部下载完成')
return download_encrypt_list
else: # 有部分视频在三次重试后依旧没有下载成功
print(f'[{class_video_name}]——下载过程中出现问题,正在重试...')
return await download_m3u8_all()


async def decrypt_m3u8_video(m3u8_encrypt_file_uri: str, key: bytes, iv: bytes):
decrypt_name = f'{m3u8_encrypt_file_uri.split("/")[-1].split(".")[0]}'
dest_decrypt_uri = f'{class_video_name}/decryption/{decrypt_name}.de.ts'
if not os.path.exists(dest_decrypt_uri):
async with aiofiles.open(m3u8_encrypt_file_uri, mode='rb') as f:
f = await f.read()
content_video_part = AES.new(key, AES.MODE_CBC, iv).decrypt(f)
async with aiofiles.open(dest_decrypt_uri, mode='wb') as f:
await f.write(content_video_part)
print(f'[{class_video_name}]——已解密第 {decrypt_name} 个片段/ 共 {len(playlist.files)} 个片段')


async def decrypt_m3u8_all():
if not os.path.exists(class_video_name + '/decryption'):
os.makedirs(class_video_name + '/decryption')
key = await requests.get(playlist.keys[0].uri)
key = key.content
iv = bytes(playlist.keys[0].iv, 'UTF-8')[:16]
decrypt_m3u8_list = [asyncio.create_task(decrypt_m3u8_video(f'{class_video_name}/downloads/{uri}', key, iv))
for uri in os.listdir(f'{class_video_name}/downloads') if uri[0] != '.'] # 忽略隐藏文件
await asyncio.wait(decrypt_m3u8_list)
print(f'[{class_video_name}]——视频全部解密完成')


def merge_m3u8_all():
download_decrypt_list = [uri for uri in os.listdir(f'{class_video_name}/decryption') if uri[0] != '.']
download_encrypt_list = [uri for uri in os.listdir(f'{class_video_name}/downloads') if uri[0] != '.']
if len(download_decrypt_list) != len(download_encrypt_list): # 判断是否有漏下的分段视频没有下载
print('解密分段视频出现问题,可能是受限于类Unix系统文件句柄数量限制导致脚本不能获取足够的文件句柄。\n '
'如果你是 Linux 或 Macos 请尝试在运行本脚本的终端内执行 "ulimit -n 5120" 命令,以解除255(Macos)/1024(Linux)数量限制')
return
with open(f'{class_video_name}/{class_video_name}.mp4', 'ab') as final_file:
print(f'[{class_video_name}]——开始拼接解密后的分段视频')
temp_file_uri_list = os.listdir(f'{class_video_name}/decryption')
temp_file_uri_list.sort(key=lambda x: int(x[:-6]))
for uri in temp_file_uri_list:
if uri[0] == '.': continue # 忽略隐藏文件
with open(f'{class_video_name}/decryption/{uri}', 'rb') as temp_file:
final_file.write(temp_file.read()) # 将ts格式分段视频追加到完整视频文件中
print(f'[{class_video_name}]——合成视频成功')


if __name__ == '__main__':
playlist = m3u8.load(m3u8_file_uri, verify_ssl=False)
del playlist.files[0] # 第一个文件为视频密钥,忽略这个文件。
asyncio.run(download_m3u8_all())
asyncio.run(decrypt_m3u8_all())
merge_m3u8_all()
print(f'[{class_video_name}]——视频文件:{os.getcwd()}/{class_video_name}/{class_video_name}.mp4')

钉钉

钉钉回放下载更简单,之后将腾讯课堂回放的脚本稍作删减就可以用于钉钉回放下载。

Ceph块设备 对RBD块设备操作LVM创建PV时报错

当映射好了RBD映像中后,要在其上创建LVM逻辑卷,在执行pvcreate时出错。报错如下:

[root@ceph-master ceph]# pvcreate /dev/rbd0
/dev/sdd: open failed: No medium found
Device /dev/rbd0 excluded by a filter.

可以看到执行创建PV时被过滤器拦截掉了,这是因为默认情况下LVM不支持rbd设备类型,那么在LVM过滤器配置中手动添加RBD类型即可。

调试模式查看详细信息:

# pvcreate -vvvv /dev/rbd0 &> /tmp/out
# less /tmp/out
....
#filters/filter-type.c:27 /dev/rbd0: Skipping: Unrecognised LVM device type 252
....

查看设备类型ID

cat /proc/devices

可以找到rbd设备类型ID编号为252,记住它后接下来在LVM过滤器配置文件中添加它。

修改LVM过滤器配置文件

vim /etc/lvm/lvm.conf

找到types参数,将rbd和252修改为如下配置:

...
# Configuration section devices.
# How LVM uses block devices.
devices {
...
# Configuration option devices/types.
# List of additional acceptable block device types.
# These are of device type names from /proc/devices, followed by the
# maximum number of partitions.
#
# Example
types = [ "rbd", 252 ]
#
# This configuration option is advanced.
# This configuration option does not have a default value defined.
...

现在尝试重新添加rbd设备作为PV:

pvcreate /dev/rbd0

现在可以成功在RBD块设备上执行创建PV操作了。

Ceph 映射RBD块设备

前提准备

你需要有一个运行着的Ceph集群,并且已创建好了一个Pool池,以此来创建新的RBD映像。

Pool池名称:rbd

Namespace命名空间名称:42team

要创建的RBD镜像名:42team.dev.yeefire.com.100G.img

新建块设备

创建块设备首先要创建Pool池,关于Pool池的创建如果你还不知道的话可以先看看这篇文章:OSD与Pool池的常见操作及管理

创建Pool池:ceph osd pool create rbd 16 16

新创建的Pool池如果要用于RBD映像存储的话最好先对其初始化并对这个Pool池设置rbd应用:

  • 初始化Pool池用于RBD存储:rbd pool init rbd
  • 为rbd池设置app应用,并标记rbd应用:ceph osd pool application enable rbd rbd

创建命名空间(非必要操作)

命名空间的存在是方便对一个存储池Pool进行更细化的用户访问控制,这样可以少创建一些存储池,使用池中命名空间来对用户进行隔离。

如果你想了解如何使用cephx认证配合命名空间对用户限制访问池中资源,请阅读:Ceph用户管理

为rbd池创建名为42team的命名空间:namespace create -p rbd --namespace 42team

创建RBD映像

到这一步为止,你已经做了如下操作:

  • 有一个正常状态的Ceph存储集群
  • 创建了一个名为rbd的存储池
  • 将rbd存储池的application应用设置为rbd
  • 可选:(为rbd池创建名为42team的命名空间)
  • 可选:(创建一个cephx认证用户,并将这个用户的osd能力限制在rbd池中的42team命名空间内)

接下来开始创建一个RBD映像

rbd create -p rbd --namespace 42team --size 100G 42team.dev.yeefire.com.100G.img

查看创建的rbd映像

rbd ls -p rbd --namespace 42team

映射RBD映像到内核模块

用 rbd 把映像名映射为内核模块。必须指定映像名、存储池名、和用户名。若 RBD 内核模块尚未加载, rbd 命令会自动加载。

例如要将rbd池中42team命名空间的42team.dev.yeefire.com.100G.imgRBD映像映射到本机:

rbd device map -p rbd --namespace 42team --image 42team.dev.yeefire.com.100G.img

至此挂载RBD映像成功,如果要查看本机已挂载的RBD映像可以执行:

rbd device ls

Nginx反向代理下载传输超过1G大文件时断开问题

问题描述

42Team社团上线下载站,使用Nginx反向代理为用户提供服务。问题的现象是当用户下载文件超过1G大小时出现断开下载连接的情况导致下载失败。

问题分析

一开始以为是Flask的流传输出了问题,调试并跟踪代码后并没有发现问题,而且直接在本地代码调试下载大文件不会出现断开情况。那么开发环境与生产环境中只相差了中间有一层Nginx反向代理,那么初步问题定位到Nginx的反向代理配置上。

经过在网上进行搜索“反向代理下载大文件失败断开连接”等关键字后找到了一篇其他人写的博文,遇到过类似的问题。

发现可能是因为超时的原因导致,因为反向代理服务器和部署下载站服务的服务器之间的网络传输速度和磁盘性能非常好,所以他们之间传递1G以上的大文件仅仅有几秒的时间,而Nginx反向代理服务器将文件传输到用户端可能需要数分钟或数十分钟,由于这之间的时间差非常大,所以超过了Nginx的默认连接超时时间,导致此问题发生

问题解决

禁用缓存

禁用缓存,客户端的每次清求都转发到被代理服务器,做法是在代理服务器的Nginx配置里面添加:

proxy_pass http://172.17.8.88:5050/;
proxy_redirect default;
proxy_buffering off;

加大Nginx服务器与另一服务器之间的超时等待时间

keepalive_timeout 15;
send_timeout 3600;

Nginx反向代理导致大文件下载失败

Ceph块设备

块是一个字节序列(例如,一个512字节的一块数据),基于块的存储接口是最常见的存储数据方法,他们基于旋转媒体,类似于硬盘、CD、软盘、甚至传统的磁带。无处不在的块设备接口使得虚拟块设备成为与Ceph这样海量存储系统交互的理想之选。

Ceph块设备是瘦接口、大小可以调整且数据被条带化存储在Ceph集群内的多个OSD上。Ceph块设备均衡多个RADOS的能力,快照、复制和一致性,Ceph的RADOS块设备用内核模块或librbd库与各个OSD交互。

ceph-block-rados-2020-08-03

Ceph 块设备靠无限伸缩性提供了高性能,如向内核模块、或向 abbr:KVM (kernel virtual machines) (如 QEMU 、依赖 libvirt 和 QEMU 的 OpenStack 和 CloudStack 云计算系统都可与 Ceph 块设备集成)。可以用同一个集群同时运营 Ceph RADOS 网关、 CephFS 文件系统、和 Ceph 块设备。

块设备的基本操作

rbd命令可以用于创建、罗列、自检和删除块设备的映像。当然也可以对映像进行克隆、创建快照并支持回滚等。

创建一个块设备存储池

在管理节点上,用ceph命令创建一个Pool池。了解更多关于Pool池可以访问OSD与Pool池的常见操作及管理

ceph osd pool create rbd 64 64

成功创建一个Pool后使用rbd工具再对这个Pool池进行初始化用于RBD。

rbd pool init <pool-name>

此处将新创建的rbdPool池进行初始化

注意:在接下来使用rbd的命令时如果需要填写<pool-name>参数的地方为空没有填写,那么默认会查找Pool池名为rbd并使用它。

创建块设备用户(非必须)

如果不指定用户的话,使用rbd命令会默认使用admin管理员访问Ceph集群,admin的用户权限最大,不应该分配给其他机器。所以最好创建一个权限尽可能小的用户访问块设备池。

osd 'allow {access-spec} [{match-spec}] [network {network/prefix}]'

osd 'profile {name} [pool={pool-name} [namespace={namespace-name}]] [network {network/prefix}]'

如果要了解更多Ceph用户有关信息,可以访问阅读Ceph用户管理

创建块设备映像

如果想要将块设备添加到某一节点,你需要先在Pool中创建一个映像文件。

rbd create --size {megabytes} {pool-name}/{image-name}

例如,在rbd这个Pool池中创建一个名为42team-webnode.img,大小为20G的一个映像:

rbd create --size 20G --pool rbd --image 42team-webnode.img

罗列磁盘映像

要罗列rbdPool存储池中的全部映像,使用下面的命令:

rbd ls {poolname}

{poolname}如果不填写,则默认使用rbd存储池。

检索映像信息

使用下面的命令来检索某一个映像的信息:

rbd info {pool-name}/{image-name}

{poolname}如果不填写,则默认使用rbd存储池。

rbd info rbd/42team-webnode.img

返回结果:

[root@vm1 ~]# rbd info rbd/42team-webnode.img
rbd image '42team-webnode.img':
size 20 GiB in 5120 objects
order 22 (4 MiB objects)
snapshot_count: 0
id: 17382bc345839
block_name_prefix: rbd_data.17382bc345839
format: 2
features: layering, exclusive-lock, object-map, fast-diff, deep-flatten
op_features:
flags:
create_timestamp: Mon Aug 3 11:03:56 2020
access_timestamp: Mon Aug 3 11:03:56 2020
modify_timestamp: Mon Aug 3 11:03:56 2020

调整块设备映像大小

Ceph块设备是瘦接口设备,只有真正写入了数据后才开始占据物理空间,直到限制到它最大的存储大小,他们的最大存储容量就是设置的--size选项的值。如果需要增加或减少Ceph块设备的存储最大尺寸,使用下面的命令:

缩小映像最大尺寸

如果要缩小块设备的映像最大存储尺寸,需要添加--allow-shrink选项,才允许缩小映像尺寸。

rbd resize -p rbd --image 42team-webnode.img -s 5G --allow-shrink

如果已使用的存储尺寸大于要缩减之后的尺寸,强行缩减块设备映像尺寸会导致数据丢失!

扩大映像最大尺寸

rbd resize -p rbd --image 42team-webnode.img -s 25G

删除块设备映像

你可以直接将块设备中的映像删除,或者先将他们移动到垃圾桶中,等待一段时间删除或者手动进行清理。

直接删除块设备映像

rbd rm {pool-name}/{image-name}

rbd rm 42team-webnode.img

{poolname}如果不填写,则默认使用rbd存储池。

延期删除映像

延期删除可以现将要删除的映像存放到垃圾池中,即便他有快照或者正被克隆的镜像引用者也可以被放入到垃圾桶池中,但是不能将他们从垃圾池中删掉。

你可以用 –expires-at 设置延期时间(默认为 now ),并且,它的延期时间没到的话是不能删除的,除非你用 –force 选项。

rbd trash mv {pool-name}/{image-name}

rbd trash mv rbd/42team-webnode.img

rbd trash mv restore-42team-webnode.img --expires-at "20200805"

之后可以通过rbd trash ls --long查看放入到垃圾池的映像有哪些,如果设立日期保护的话还可以看到保护到期的时间。

还原块设备映像

当你突然醒悟不该放弃某个映像时,你当然可以从垃圾池中将映像还原!但是前提时你将它放入到了垃圾池而不是直接删除掉他们。

rbd trash restore {pool-name}/{image-id}

在还原映像时需要使用image-id进行还原。可以使用rbd trash ls查看image映像id。

[root@vm1 ~]# rbd trash ls
17382bc345839 42team-webnode.img
[root@vm1 ~]#

rbd trash restore 17382bc345839 --image restore-42team-webnode.img

在还原的同时,还可以指定--image选项对垃圾池内的映像重命名。

彻底删除在垃圾池中的映像

rbd trash rm {pool-name}/{image-id}

使用rbd trash rm命令可以将在垃圾池中的映像彻底删除,如果你设置了延期时间–expires-at ,那么没到延期时间内直接删除是不可以的,除非使用 –force 选项强制删除。

拍摄镜像快照

快照是某映像在一个特定时间点的一份只读副本。Ceph块设备的一个高级功能是可以为映像创建快照来保留历史。Ceph也支持分层快照,这样可以更快速的的克隆一个映像(如VM映像)。Ceph的快照功能还支持rbd命令和多种高级接口,包括 QEMU 、 libvirt 、 OpenStack 和 CloudStack

因为RBD不关心文件系统,如果没有与map挂载着的计算机协调的话,快照就是crash-consistent的。所以,在拍摄快照前应该将这个映像的I/O操作暂停,如果这个映像还包含文件系统,在拍摄这个包含文件系统的映像前系统还必须处于一致性状态,否则就要用fsck来修复它了…

可以使用fsfreeze命令冻结I/O。对于虚拟机来说,qemu-guest-agent 可在创建快照时自动冻结文件系统。

ceph-snap-ins-2020-08-06

快速操作快照

接下来的过程演示了如何用 rbd 命令创建、罗列、和删除快照。

创建快照

rbd snap create命令创建快照,需要声明存储池名和映像名。

rbd snap create {pool-name}/{image-name}@{snap-name}

如为rbd/5G.img拍摄快照:

rbd snap create 5G.img@2008050810

罗列快照

要列出某一个映像的快照,需要指定存储池名和映像名。

rbd snap ls {pool-name}/{image-name}

例如:

rbd snap ls 5G.img

[root@vm1 ~]# rbd snap ls 5G.img
SNAPID NAME SIZE PROTECTED TIMESTAMP
4 2008050810 5 GiB Wed Aug 5 08:10:55 2020

回滚快照

要用rbd回滚到某一快照,使用rbd snap rollback命令。回滚快照时要求该映像不能处于map状态!不应该有任何资源占用这个映像。

rbd snap rollback {pool-name}/{image-name}@{snap-name}

例如:

rbd snap rollback 5G.img@2008050810

把映像回滚到一快照的意思是,用快照中的数据覆盖映像的当前版本,此过程花费的时间随映像尺寸增长。从快照克隆要快于回滚到某快照。这也是回到先前状态的首选方法。

删除快照

删除某映像的一个快照

使用rbd snap rm命令删除某一映像的快照:

rbd snap rm rbd/5G.img@2008050810

删除后可以再查看一下当前快照,检查是否成功删除:

rbd snap ls rbd/5G.img

删除某映像的全部快照

当你要删除一个映像的全部快照时,使用rbd snap purge命令:

rbd snap purge {pool-name}/{image-name}

rbd snap purge rbd/5G.img

克隆快照映像

可以克隆一个映像,在原有映像基础之上建立新的分支。不过需要了解分层的概念,想要克隆一个快照必须先创建快照,并且将其保护,之后才能克隆快照。

了解分层

ceph-clone-2020-08-06

Ceph 块设备的分层是个简单的过程。你必须有个映像、必须为它创建快照、必须保护快照,执行过这些步骤后,你才能克隆快照。

克隆出的映像包含到父快照的饮用、存储池ID、映像ID和快照ID。包含存储池ID意味着你可以把存储池内的快照克隆到别的存储池中。

分层可以应用于以下方面:

  • 映像模版:块设备分层的一个常见用法是创建一个主映像及其快照,并作为模版以供克隆。例如管理员会创建一个Linux发行版的映像,之后周期性的升级维护(比如执行了dnf update操作之后等)。等映像文件稳定可用后,用户可以克隆任意快照。
  • 拓展模板:更高级的用法包括拓展映像模板,让它包含比基础映像更多的信息。例如,首先可以克隆一个基础映像,然后再此基础之上安装新的软件包(如数据库、博客平台、内容管理系统等),之后在此拓展上再次创建快照,拍下的快照可以像基础映像一样更新。
  • 模版存储池:块设备分层的一种用法是创建一个存储池,其中包含作为模版的主映像和那些模版快照。然后把只读权限分给用户,这样他们就可以克隆快照了,而无需分配此存储池内的写和执行权限。
  • 映像迁移/恢复:块设备分层的一种用法是把以存储池内的数据迁移或恢复到另一个存储池。

保护快照

克隆的映像要访问父快照。如果那个用户不小心删除掉了父快照,那么所有依赖这个父快照的克隆映像都会损坏。为了防止数据丢失,必须先保护快照,然后再当作父快照进行克隆。

rbd snap protect {pool-name}/{image-name}@{snapshot-name}

如下:

rbd snap protect 5G.img@202008051308

之后查看该映像的所有快照:

rbd snap ls 5G.img

[root@vm1 ~]# rbd snap ls 5G.img
SNAPID NAME SIZE PROTECTED TIMESTAMP
10 202008051308 5 GiB yes Wed Aug 5 13:08:03 2020
11 202008051309 5 GiB Wed Aug 5 13:08:05 2020
12 2020080513010 5 GiB Wed Aug 5 13:08:10 2020

可以看到刚刚被保护的快照,在此处有了标记,接下来尝试能否删除这个快照:

rbd snap rm 5G.img@202008051308

ceph-snap-protect-rm-2020-08-06

结果显而易见,当快照被保护的情况下是不允许被删除的。这样我们就可以在这个快照的基础上进行克隆全新的映像!

克隆映像快照

要克隆快照,你得指定父存储池、映像、和快照,还有子存储池和映像名。克隆前必须先保护快照,否则不允许克隆。

rbd clone {pool-name}/{parent-image}@{snap-name} {pool-name}/{child-image-name}

例如克隆我们刚刚保护的那个快照,并且把克隆后的映像叫做5G_new.img:

rbd clone 5G.img@202008051308 rbd/5G_new.img

你可以把一存储池中的映像的快照克隆到另一个存储池。例如,你可以把一存储池中的只读映像及快照当作模版进行维护,之后(比如映像调试完毕后)可以将其克隆到另一个存储池中进行发布使用。

现在,可以查看以下刚刚克隆的新映像的信息:

rbd ls --long

rbd info 5G_new.img

ceph-clone-ls-2020-08-06
ceph-clone-rbd-info-2020-08-06

罗列快照的后代

rbd children {pool-name}/{image-name}[@{snapshot-name}]

例如:

rbd children rbd/5G.img

取消快照保护

删除快照前,必须先需要快照保护。另外如果有其他的子映像使用着这个快照,那么你不能删除这个快照。除非你将引用这个快照的子映像执行拍平的操作。

rbd snap unprotect {pool-name}/{image-name}@{snapshot-name}

无法取消保护一个被克隆的子映像使用的快照,除非你将克隆后的映像拍平。
ceph-snap-unprotect-1-2020-08-06

拍平克隆的映像

克隆的映像一直保留着对父快照的引用,所以你无法取消保护一个被引用的父快照。如果你要从子克隆删除到父快照的这些引用,你可以把引用的父快照信息完整的复制到子克隆中,也就是拍平它。拍平克隆品的时间因快照尺寸而不同,要删除快照或者取消保护快照,必须将子映像拍平。

rbd flatten {pool-name}/{image-name}

例如:

rbd flatten rbd/5G_new.img

拍平子映像后,就不会再引用父快照的信息了。此时,你可以将父快照解除保护并删除。