GitLab CI 使用笔记

CI/CD 不必多说。

gitlab ci

CI/CD 解决的问题:

  • 重复劳动
  • 等待时间
  • 手工出错

基本概念

gitlab CI 依赖于项目根目录中定义的 .gitlab-ci.yml 文件,这个文件定义了 GitLab CI 应该做的事情。每次提交代码 GitLab 会检查该文件,然后将该文件定义的内容提交给 GitLab Runner 执行。

CI/CD

  • CI : Continuous integration,持续集成,代码有改动时触发编译、测试、打包等一系列构建操作,最后生成一个可部署的构件。指开发⼈人员在特定分⽀支(频繁)提交代码,⽴立即执⾏行行构建和单元测试,代码通过测试标准后集成到主⼲干的过程。强调的是分⽀支代码的提交、构建与单元测试。
  • Continuous Delivery,持续交付,在持续集成的基础上,将构建的代码部署到「类⽣生产环境」
  • Continuous Deployment, 持续部署,CI 之后自动化地部署或交付给客户使用。

pipeline

gitlab-ci 中配置的所有可执行的 job 称为 pipeline,Pipeline 可以认为是一次构建过程。Pipeline 中可以包含多个 stage.

gitlab-ci-pipeline

在 GitLab 后台可以看到如图,整个过程称为一个 pipeline,这个 pipeline 包括两个 stage(阶段)。每个阶段就只有一个任务,gitlab-ci 在运行时只有当一个 stage 中所有的任务都执行完成才会进入下一个 stage.

首先来对 .gitlab-ci.yml 文件有一个整体的了解。

# 定义 stages
stages:
  - test
  - build

# 定义 job
job1:
  stage: test
  script:
    - echo "test stage"

job1_1:
  stage: test
  script:
    - echo "test stage: job1_1"

# 定义 job
job2:
  stage: build
  script:
    - echo "build stage"

stage

stage 可以理解为阶段,是 gitlab-ci 的概念,流程中的阶段,可以包括测试,编译,发布,部署等,在 .gitlab-ci.yml 文件中会用到。

  • GitLab CI 文件中必须包含至少一个 stage
  • 多个 stage 按照顺序执行
  • 如果其中任何一个 stage 发生错误,之后的所有 stage 都不会被执行。
  • 同样只有所有的 stage 都成功,Pipeline 才会成功

定义:

- stages:
  - build
  - deploy
  - release

job 或者 app

job 或者又被称为 app,由 job 组成 gitlab-ci 的 stage 阶段,多个 job 可以并发执行。

  • 同一个 stage 下的 job 会并行执行
  • 同一个 stage 下的 job 都执行成功,该 stage 才会成功
  • 如果 job 执行失败, 那么该 stage 失败,pipeline 失败,该次构建过程失败

举例:

build_front:
  stage: build
build_backend:
  stage: build

上面两个 app (build_front, build_backend) 将会在 build 阶段并发执行。

variables

gitlab-ci 中集成了很多默认的变量,可以通过 variables 关键字来定义自己的变量,也可以在 gitlab 提供的界面上配置。gitlab 提供的 UI 可以配置全组或者 project 级别的环境变量。

  • group 级别
  • project 级别

比如一些敏感的信息,比如 Nexus 密码,Docker Registry 密码或者密钥之类等等

GitLab Runner

GitLab CI 中是 Runner 真正在执行 .gitlab-ci.yml 中定义的任务,Runner 可以是虚拟机,物理机,Docker 容器或者容器集群。GitLab 和 GitLab Runner 直接通过 API 通信,所以需要保证 GitLab 和 Runner 直接可以通过 HTTP 进行通信。

GitLab Runner 可以分为两种类型: Shared Runner (共享型) 和 Specific Runner(指定)

  • Shared Runner: 所有工程都可以使用,只有系统管理员可以创建
  • Specific Runner: 只有特定的项目可以使用

Install Runner

GitLab Runner 的安装参考官方网站 即可,代码也是开源的.

常用关键词

全部的关键词可以在官网 查看。

script

最常用的一个关键词了,script 定义具体需要执行的任务。

before_script

before_script 定义在每一个 job 之前的任务,必须是 Array 类型。

after_script

after_script 每一个 job 之后执行,即使 job 失败了也会执行,Array 类型。

cache

定义需要缓存的文件或者路径。

Use case

对部分文件修改判断是否触发该阶段

有时候没有修改一些可能需要重新跑 build 的代码,不想 GitLab Runner 空跑,可以使用 only 关键字,以及 change 关键字实现只有部分文件改动后再触发 build.

only: # 下面的条件都成立
  refs: # 下面的分支中任一分支改变
    - release
  changes: # 下面的文件中任一文件发生改变
    - .gitlab-ci.yml
    - Dockerfile

当 release 分支改变,同时 .gitlab-ci.yml 文件或者 Dockerfile 文件发生改变时,触发这个阶段的执行。

多个模块编译方式不同

假如一个项目中集成了很多个模块,而每一个模块中的内容编译方式都不同。那么可以使用 gitlab-ci 提供的 include 关键字,对各个模块进行分拆。在每一个模块下放置 .gitlab-ci.yml 文件,然后再到根目录中创建 .gitlab-ci.yml 文件使用 include 关键字引入进来,对各个模块进行解耦。

include:
  - local: module1/.gitlab-ci.yml
  - local: module2/.gitlab-ci.yml

模板

集成 sonar

Build:
 stage: build
 script:
 - echo 'build projects'
 - "mvn $MAVEN_CLI_OPTS clean compile -Dmaven.test.skip=true"
 - 'mvn $MAVEN_CLI_OPTS -U clean package -Dmaven.test.skip=true'
 - 'mvn $MAVEN_CLI_OPTS sonar:sonar -Dsonar.projectKey=projectname -Dsonar.host.url=http://url -Dsonar.login=xxxxx'

Test:
 stage: test
 script:
 - echo 'test projects'
 - 'mvn $MAVEN_CLI_OPTS clean test'
 only:
  - master
  - staging

reference


2020-03-31 gitlab , git , continuous-integration , continuous-delivery , continuous-deployment , programming

使用命令行远程网络唤起主机

在 Linux 下可以通过 etherwake 命令来网络唤醒设备。

sudo apt install etherwake

检查主机是否支持网络远程唤醒

首先检查 BIOS 中设置,Wake on LAN 是否开启。一般在 BIOS > Power Management > “Wake On LAN” 这个选项下。然后重启进入系统,用如下命令查看网卡 eth0 是否开启了 Wake on LAN:

ethtool eth0

输出:

Settings for eth0:
		Supported ports: [ TP ]
		Supported link modes:   10baseT/Half 10baseT/Full
								100baseT/Half 100baseT/Full
								1000baseT/Full
		Supported pause frame use: Symmetric
		Supports auto-negotiation: Yes
		Supported FEC modes: Not reported
		Advertised link modes:  1000baseT/Full
		Advertised pause frame use: Symmetric
		Advertised auto-negotiation: Yes
		Advertised FEC modes: Not reported
		Speed: 1000Mb/s
		Duplex: Full
		Port: Twisted Pair
		PHYAD: 1
		Transceiver: internal
		Auto-negotiation: on
		MDI-X: off (auto)
		Supports Wake-on: pumbg
		Wake-on: g
		Current message level: 0x00000007 (7)
							   drv probe link
		Link detected: yes

结果中可以一眼就看到:

Supports Wake-on: pumbg
Wake-on: g

如果没有看到这个字样,或者是 off 状态,需要手动启动一下:

ethtool -s eth0 wol g

说明:

  • -s NIC, 我这里的 eth0 是网络接口的设备名,根据不同的设备填写不同,可以通过 ifconfig 来查看
  • wol g 表示设置 Wake-on-LAN 选项使用 MagicPacket.

使用命令远程唤醒

在 Linux 下执行如下命令唤醒设备:

sudo apt install wakeonlan
wakeonlan MAC_ADDRESS

或者

etherwake MAC_ADDRESS

可以通过 ping 命令和 arp 命令来获取局域网中的设备 MAC 地址:

ping -c 4 SERVER_IP && arp -n

reference


2020-03-29 cli , wake-on-lan , linux , etherwake , ethernet , network

Cloud-init 初始化虚拟机配置

在安装 Proxmox 后在它的文档中了解到了 cloud-init。所以就来梳理一下,什么是 cloud-init,它解决了什么实际问题,以及最重要的它该怎么用。

cloud-init 是什么

cloud-init 是一套工业标准为的是统一不同操作系统发行版在跨平台的云端服务器上初始化安装的流程。 cloud-init 是运行在 Guest machine 中,并在初始化时将一些自定义的配置应用到 Guest machine 中的应用程序。想象一下,假如你是一个云主机提供商,每天都需要为客户初始化成千上万台虚拟主机,这些机器可能使用不用的操作系统,可能根据客户需求设定不同的 IP 地址,不同的 SSH key,以及设置不同的 hostname 等等,这个时候需要怎么办,cloud-init 就是为了解决这个问题而诞生的。

cloud-init 最早由 Ubuntu 的开发商 Canonical 开发,现在已经支持绝大多数 Linux 发行版和 FreeBSD 系统。而目前大部分的公有云都在用 cloud-init 初始化系统配置,cloud-init 也支持部分私有云 (KVM, OpenStack, LXD 等等) 1,已经成为了事实上的标准。而这里就回到了 Proxmox,因为 Proxmox 是用来部署和管理虚拟机的平台,所以天然的适合 cloud-init 的使用场景,甚至可以说是不可或缺的一部分。

当我们在 AWS,或者 Google Cloud 这些公有云中申请计算资源的时候,云服务的提供商总是会叫我们选择一个系统镜像,然后做一些基础设置 (Hostname, SSH key 等等),然后在此基础上进行系统创建。cloud-init 正是在这个背景下诞生,自动化将用户数据初始化到系统实例中。

cloud-init 的主旨是定义一些独立于操作系统的配置,比如 hostname, networking configuration 等等。

cloud-init 特性:

  • 设置默认的 locale
  • 设置 hostname
  • 生成并设置 SSH 私钥
  • 设置临时的挂载点

Boot Stages

cloud-init 对系统的初始化分为这几个阶段:

  • Generator
  • Local
  • Network
  • Config
  • Final

Generator

当系统启动的时候,generator 会检查 cloud-init.target 是否需要启动。默认情况下,generator 会启动 cloud-init. 但是如下情况 cloud-init 不会在开机运行:

  • /etc/cloud/cloud-init.disabled 文件存在时
  • 当内核命令发现文件 /proc/cmdline 包含 cloud-init=disabled 时,当在容器中运行时,内核命令可能会被忽略,但是 cloud-init 会读取 KERNEL_CMDLINE 这个环境变量

Local

Local 阶段会在挂载根分区 / 时,立即执行

cloud-init-local.service

Local 阶段的目的是:

  • 查找 local data source
  • 将网络配置应用到本地

大多数情况下,这个阶段就只会做这些事情。它会在 datasource 中查找,并应用网络配置。网络配置可能从这些地方来:

  • datasource: 云端通过 metadata 提供
  • fallback: 通过 dhcp on eth0,在虚拟机内自行通过 DHCP 获取 IP
  • none: 网络配置可以通过 /etc/cloud/cloud.cfg 中配置 network: {config: disabled} 来禁用

如果是该实例的第一次启动,那么被选中的网络配置会被应用,所有老旧的配置都会会清除。

该阶段需要阻止网络服务启动以及老的配置被应用,这可能带来一些负面的影响,比如 DHCP 服务挂起,或者已经广播了老的 hostname,这可能导致系统进入一个奇怪的状态需要重启网络设备。

cloud-init 然后再继续启动系统,将网络配置应用后启动。

Network

在 local 阶段后,网络服务启动后,启动

cloud-init.service

该阶段需要所有的网络配置已经被应用,并且网络在线,然后才会应用所有的 user-data

  • 递归检索任何 #include 或者 #include-once 包括 http
  • 解压缩任何压缩的内容
  • 运行任何找到的 part-handler

该阶段运行 disk_setmounts 模块,可能会分区并格式化任何配置挂载点(比如 /etc/fstab中)的磁盘。这个模块不能再早运行,因为有可能有些信息来源于网络,只有等网络信息获取到后才能执行。比如用户可能在网络资源中提供了挂载点配置信息。

在一些云服务中,比如 Azure,这个阶段会创建可以被挂载的文件系统。

part-handler 也会在这个阶段运行,包括 cloud-config bootcmd

Config

在网络启动后运行:

cloud-config.service

这个阶段只会运行 config 模块,不会对其他阶段产生影响的模块在这里运行。

Final

启动的最后阶段运行:

cloud-final.service

用户登录系统后习惯于运行的脚本在这个阶段运行,包括:

  • 包安装
  • 配置管理的插件 (puppet, chef, salt-minion)
  • 用户脚本(包括 runcmd)

Install and use cloud-init under Proxmox

cloud-init 一般是安装在虚拟机中的,Ubuntu 系的系统直接安装即可:

apt install cloud-init

绝大部分的发行版会提供开箱即用 (ready-to-use) 的 Cloud-Init 镜像(一般以 .qcow2 文件发布),所以你可以下载这些文件,然后直接导入。比如说 Ubuntu 提供的镜像:https://cloud-images.ubuntu.com/

虽然大部分发行版都提供了开箱即用的 Cloud-Init 镜像,但还是推荐如果要更高的定制化需求可以自己来制作符合自己需求的镜像。

在 Proxmox 下,一旦制作好了 Cloud-Init 镜像,推荐将该镜像转换成 VM template, 通过 template 可以快速创建虚拟机。

# download
wget https://cloud-images.ubuntu.com/bionic/current/bionic-server-cloudimg-amd64.img
# create a new vm
qm create 9000 --memory 2048 --net0 virtio,bridge=vmbr0
# import the downloaded disk to local-lvm storage
qm importdisk 9000 bionic-server-cloudimg-amd64.img local-lvm
# finally attach the new disk to the VM as scsi drive
qm set 9000 --scsihw virtio-scsi-pci --scsi0 local-lvm:vm-9000-disk-1

Add cloud-init CDROM drive

qm set 9000 --ide2 local-lvm:cloudinit

为了从 Cloud-Init 镜像直接启动需要设置 bootdisk 参数到 scsi0,然后设置 BIOS 从 disk 启动

qm set 9000 --boot c --bootdisk scsi0

然后配置 serial console 将其作为显示输出,这是 OpenStack 镜像必须设置的内容

qm set 9000 --serial0 socket --vga serial0

Prepare template

最后就可以将 VM 转换成 template,然后通过该模板就可以快速创建 clones,从 VM templates 部署系统要远远快于一个完整的 clone:

qm template 9000

Deploying Cloud-Init Templates

可以使用如下命令从 template 中克隆系统:

qm clone 9000 123 --name ubuntu2

设置 SSH,及网络(这里的 IP 地址需要改成自己的网络环境的地址):

qm set 123 --sshkey ~/.ssh/id_rsa.pub
qm set 123 --ipconfig0 ip=10.0.10.123/24,gw=10.0.10.1

配置文件地址

cloud-init 配置文件在:

/etc/cloud/cloud.cfg
/etc/cloud/cloud.cfg.d/*.cfg

cloud-init 在配置文件 /etc/cloud/cloud.cfg 中定义了各个阶段需要执行的任务,任务以 module 形式组织。 cloud.cfg 中指定了 set_hostname 这个 module, 则表示 cloud-init 会执行设置 hostname 的任务,但是具体设置的内容由 metadata 指定。

cloud-init 的日志在:

/var/log/cloud-init-output.log: 每一个阶段的输出
/var/log/cloud-init.log: 每一个操作更详细的调试日志
/run/cloud-init: contains logs about how cloud-init decided to enable or disable itself, as well as what platforms/datasources were detected. These logs are most useful when trying to determine what cloud-init ran or did not run.

数据存放在:

/var/lib/cloud

在 Ubuntu Server 18.04 中设置静态 IP 地址

在安装 ubuntu server 18.04 的时候没有选择用静态地址,所以路由器 DHCP 随机分配了一个,然后进系统才想起来配置一下静态地址。传统的做法是修改 /etc/network/interfaces 文件,配置接口的静态地址即可。不过网上搜索一番学习之后发现了一个新方法,使用 netplan 来做修改。2

修改 /etc/netplan/50-cloud-init.yaml 文件,原来的 DHCP 配置可以看到 dhcp4: yes 这一行配置的是 yes,现在修改成这样:

network:
	ethernets:
		ens18:
			dhcp4: no
			addresses: [192.168.2.10/24]
			gateway4: 192.168.2.1
			nameservers:
					addresses: [114.114.114.114, 8.8.8.8]
	version: 2

然后应用到接口:

sudo netplan --debug apply
sudo netplan apply

这里千万要小心配置,如果配错可能导致无法连上系统的!

reference


2020-03-28 proxmox , virtual , virtual-machine , cloud-init , ubuntu , linux , openstack

BitTorrent 协议中的 BenCode 编码

在了解 BitTorrent 协议的时候,想着 .torrent 文件是如何生成的,所以就找了几个 CLI,比如 transmission-climktorrent这两个开源的制作 torrent 文件的开源项目,发现他们就是按照一种约定的格式来生成文件。而这个约定的结构中就少不了现在要谈的 BenCode 编码。

BitTorrent 协议使用 .torrent 文件来描述资源信息。.torrent 文件使用一套 BenCode 编码来对信息进行描述。

What is BenCode

BenCode 是用于编码 torrent 文件的一种编码格式。BenCode 支持四种数据类型:

  • 字符串 String
  • 整数 Integer
  • 数组 List
  • 字典 Dictionary

需要注意的是 BenCode 只用 ASCII 字符进行编码,如果是非 ASCII 码,BenCode 会用一种编码方式将其转换成 ASCII 码。

字符串

在编码字符串时 BenCode 选择将字符长度编码在其中:

<Length>:<Content>

比如 6:string 就表示 string 本身。其中 6 表示的是字符串长度。长度使用十进制表示。

整数

整数编码时在前后加 ie,比如:

i123e

表示整数 123 . 这种方式也可以表示负数:i-1e.

不过需要注意的是 i-0e, i03e 这样的表示是非法的,但是 i0e 是合法的,表示整数 0 .

数组

列表前后用 le 标识。列表中的元素可以是 BenCode 支持的任何一种类型。比如要编码字符串 content 和数字 42:

l7:contenti42ee

注意这里每个类型的边界都有定义清楚。字符串可以用长度来限定边界,但是整数一定需要 ie 来限定边界。

字典

字典类型可以保存一对一的关系,在 BenCode 中 KEY 必须为字符串类型,而 VALUE 可以是 BenCode 支持的任意一种类型。字典编码时用 de 限定范围。

另外需要注意,字典中 KEY 和 VALUE 必须相邻,字典依照 KEY 的字母序排序。

比如要定义 “name” -> “Ein Verne”, “age” -> 18, “interests” -> [“book”, “movie”]

首先要到 KEY 进行排序 “age”, “interests”, “name”

3:age9:Ein Verne
9:interestsi18e
4:namel4:book5:moviee

然后把上面的 KEY VALUE 连接起来,并在前后加上字典的 de 限定。

d3:age9:Ein Verne9:interestsi18e4:namel4:book5:movieee

总结一下

类似 数据 编码
int -42 i-42e
string ‘span’ 4:spam
list [‘XYZ’, 432] l3:XYZi432ee
dict {‘XYZ’: 432} d3:XYZi432ee

torrent 文件

在了解了 BenCode 的编码后,用纯文本文件打开 .torrent 文件就能知道一二了。本质上 torrent 文件就是一个用 BenCode 编码的纯文本文件,torrent 在 BitTorrent 协议中又被称为 metainfo。

metainfo 是一个 BenCode 编码的字典:

announce
	tracker 的地址
info
	字典,单文件和多文件略有不同

torrent 文件中的所有字符串必须是 UTF-8 编码的。

单文件

我在本地新建了一个 README.md 文件,然后用如下命令创建一个 torrent 文件 “test.torrent”.

mktorrent -a http://announce.url -c "This is comments" -l 18 -o "test.torrent" -p -v README.md

然后查看 cat test.torrent 内容:

d8:announce19:http://announce.url7:comment16:This is comments10:created by13:mktorrent 1.013:creation datei1585360743e4:infod6:lengthi5e4:name9:README.md12:piece lengthi262144e6:pieces20:h7@xxxxxlxx]7:privatei1eee

拆解这个编码,先分段开。

d
 8:announce -> 19:http://announce.url
 7:comment -> 16:This is comments
 10:created by -> 13:mktorrent 1.0
 13:creation date -> i1585360743e
 4:info
  d
   6:length -> i5e
   4:name -> 9:README.md
   12:piece length -> i262144e
   6:pieces -> 20:h7@xxxxxxxxx
   7:private -> i1e
  e
e

拆解后可以看到 info 字典中有这么几项:

  • length 指的是整个文件的大小
  • name 下载的文件名
  • piece length 整数,BitTorrent 文件块大小
  • pieces 字符串,连续存放所有块的 SHA1 值,每一个块的 SHA1 值长度都是 20,这里因为文件本身比较小所以只有一块
  • private 整数,标记 torrent 是否私有

注:pieces 中有些特殊字符,在文章中用其他字符替换了。

多文件

多文件时 info 字典中会有一个 files 列表,这个列表由字典组成,每一个字典中是文件的内容,包括文件名和文件长度。

比如对当前文件夹下 README.mdREADME1.md 两个文件制作 torrent.

mktorrent -a http://announce.url -c "This is comments" -l 18 -o "test.torrent" -p -v .

得到的 torrent 文件:

d8:announce19:http://announce.url7:comment16:This is comments10:created by13:mktorrent 1.013:creation datei1585361538e4:infod5:filesld6:lengthi5e4:pathl9:README.mdeed6:lengthi0e4:pathl10:README1.mdeee4:name1:.12:piece lengthi262144e6:pieces20:rhr7r@rorrrlrrrrrrrr7:privatei1eee

拆解一下:

d
 8:announce -> 19:http://announce.url
 7:comment -> 16:This is comments
 10:created by -> 13:mktorrent 1.0
 13:creation date -> i1585361538e
 4:info ->
  d
   5:files -> l
               d
			    6:length -> i5e
			    4:path -> l 9:README.md e
			   e
			   d
			    6:length -> i0e
			    4:path -> l 10:README1.md e
			   e
			  e
   4:name -> 1:.
   12:piece length -> i262144e
   6:pieces -> 20:rhrxxxxxxxxrrrrrr
   7:private -> i1e
  e
e

多文件时 info 字典中的内容稍微多一些。

  • files 是多个文件的信息,其中包括了文件长度和路径。

相关库

构造好字典之后,使用如下库调用即可。

客户端

可以对 torrent 文件进行编辑的客户端:

reference


2020-03-28 bittorrent , bencode , encode , encoding

在 Proxmox VE 上使用 qm 命令管理虚拟机

qm 是 [[Proxmox VE]] 系统上用来管理 Qemu/Kvm 虚拟机的命令。可以用这个命令来创建销毁虚拟机,也可以用它来控制虚拟机的启动,暂停,继续和停止。另外也可以用 qm 命令来设定虚拟机的配置。qm 命令也可以用来创建和删除虚拟磁盘 (virtual disks).

Usage

使用已经上传到 local storage 的 iso 文件来在 local-lvm storage 上创建一个 4G IDE 的虚拟磁盘。

qm create 300 -ide0 local-lvm:4 -net0 e1000 -cdrom local:iso/proxmox-mailgateway_2.1.iso

启动 VM

qm start 300

发送一个停止请求,并等待 VM 停止:

qm shutdown 3000 && qm wait 300

等待 40 秒:

qm shutdown 3000 && qm wait 300 -timeout 40

Configuration

虚拟机的配置文件可以在 /etc/pve/qemu 文件找到。

配置文件都是纯文本,你可以用任何编辑器来编辑。不过建议用 qm 命令或者通过界面来进行修改。对配置的任何修改都需要重启 VM 才能生效。


2020-03-25 proxmox , pve , linux , debian , qm , vm

如何根据自身情况选购硬盘

因为加入了一些 PT 的关系,本地的硬盘空间立即捉襟见肘,毕竟有些蓝光原盘动不动就 40+GB,所以陆陆续续给威联通也加了一些硬盘,之前一直买的是酷狼的 4T 盘,但是用了一年快两年的样子竟然挂了,这是我最初买的那一块所以也折腾了一下,因为系统和一些配置都在这一块盘上。所以强烈建议重要资料一定多处备份,不仅需要通过本地冗余备份,最好也多地备份,比如本地和其他云端备份服务实时同步。

再回到这次的主题,关于如何选购一块硬盘。打开京东能看到主流的硬盘厂商提供了种类丰富的各种用途的磁盘。但对于消费者而言,很多人其实并不知道其中的具体技术细节。很多人可能知道酷狼是 NAS 盘,酷鱼是普通家用盘,但谁也没有具体分析过这二者的区别,商家宣传也不会刻意宣传技术细节。

硬盘技术

硬盘的技术最早在 1956 年被 IBM 发明,之后便迅速成为了 60 年代通用计算机的组成部分 1。 历史上最多的时候有超过 200 家硬盘制造厂商 2,经过兼容合并后目前市场上比较著名的就只有 Seagate, Toshiba 和 Western Digital 了。再之后的故事大家都知道了,随着 SSD(Solid-state Drive) 的兴起,尤其是 NAND 技术的发展,HDD 逐渐式微,但不可否认的是 HDD 目前依然保留着自己在计算机领域的地位。

目前市场是两个主要的硬盘大小就是 3.5 寸,主要给台式机用,和 2.5 寸主要给笔记本用。HDD 通过 PATA(Parallel ATA), SATA(Serial ATA, 600MB/s), USB 和 SAS(Serial Attached SCSI, 12Gb/s) 接口和其他硬件系统连接。

主要构造

我们知道计算机的世界其实是一个二进制的世界,底层都是 0 和 1 的无尽组合,对于数据来说也是,那么作为二进制数据的存储设备硬盘而言,就是要记录下 0 和 1 的组合。在网上可以看到很多的硬盘拆解的图片,能看到一个大大的一个像 CD 一样的盘片,在盘片上会有很多磁性物质,通过盘片的快速旋转和磁头的移动来读写数据。但实际上可能要更加复杂一些。

硬盘的主要构造:

main components of hdd

说明:

  • Platter: 磁盘盘片,真正用来存储数据的地方,磁盘由非磁性材料制成,通常为铝合金、玻璃或陶瓷。它们被涂上一层浅浅的磁性材料,深度通常为 10-20 纳米,外层有一层碳保护层。盘片在硬盘正常工作时以非常高的速度旋转。
  • HEAD: 磁头,盘片高速旋转时用来读取或者写入数据,磁头和盘片之间有一个纳米级别的空隙,所有的磁头连接在一个控制器上,控制器负责磁头的运动,磁头可以沿着盘片的半径方向(斜切向)运动。每一个磁头同一时刻必须是同轴的(也就是从上问下看磁头任何时候都是重叠的,一起移动)
  • Spindle: 主轴
  • Actuator: 读写臂,操作硬盘磁头在介质表面进行数据读写的组件,每一个记录磁头位于移动读写臂的尾端
  • Actuator Arm: 磁头臂
  • Actuator Axis: 磁头轴

hard drive magnetic head

上面也提到盘片是真正用来存储数据的地方,那么盘片是如何做到的呢?盘面和磁带的原理比较相似,在磁盘的表面有一层磁性材料,而磁头通常是线圈缠绕在磁芯上

  • 在写入数据时,磁头线圈通电,周围产生磁场,电流的方向改变会引发磁场的变化,磁场会磁化磁盘表面的磁性物质。切换不同的磁场方向,磁性颗粒的方向也会不同。那么其方向的不同就可以来代表二进制世界的 0 和 1。
  • 写数据时同理,磁头线圈切割磁感线产生了感应电流,磁性材料的磁场方向不同,电流方向也不同,磁头通过感应旋转的盘片上磁场的变化来读取数据

虽然原理很简单,但是盘片,磁头,以及机械内部的制作都是需要非常精密的工艺和材料的。

盘片

具体再看纵向每一个盘片之间。

magnetic hard disk mechanism

图片源自 Cameron Hart

说明:

所有的盘片都固定在主轴上,所有盘片之间都是平行的,每一个盘片的存储面都有一个磁头,现在主流的硬盘盘面都会有上下两面。

  • Arm assembly 组合臂,控制磁头的机械结构
  • track 磁道,盘片上的同心圆叫做磁道,磁道从外向里进行编号,从 0 开始,大容量的磁盘可能有更多的磁道。 磁头靠近主轴的最内圈,线速度最小,不存放任何数据,称为 Landing Zone。离主轴最远的就是 0 磁道,数据从最外圈开始存储。
  • sector 扇区,每一段圆弧叫做扇区
  • cylinder: 柱面,所有盘面上同一磁道构成的一个圆柱称为柱面,每个圆柱上的磁头从上到下,从 0 开始编号。数据的读写在柱面进行,磁头读写数据首先在同一柱面 0 磁头开始,依次向下在同一柱面不同的盘面的磁头上操作,同一柱面所有的磁头全部读写完后磁头才转移到下一个柱面。

操作系统以扇区的形式将信息存储在硬盘上,每个扇区包括 512 字节的数据和一些其他信息。每一个扇区有两个部分数据:

  • 存储数据的地点标识符
  • 存储数据的数据段,包括数据和数据校验 ECC 纠错码

扇区头标,包括:

  1. 盘面号(或者又叫做柱面号),在第几个盘面的位置;
  2. 柱面号(又被称为磁头号),用来确定磁头径向,在盘面中的位置;
  3. 扇区号,在磁道上的位置

这三个部分可以唯一确定一块数据的具体地址。

盘面区域

盘片盘面区域

hard drive sectors

  • Disk Sector 扇面
  • Cluster 簇,物理相邻的几个扇区称为一个簇,操作系统读写磁盘的基本单位是扇区,但文件系统的基本单位是簇。簇的大小一般 4K, 8K ,16K,32K, 64K 等,簇越大存储性能越好,但空间浪费严重;簇越小性能相对越低,空间利用率高。

硬盘读写数据过程

在了解了硬盘的物理结构后,再来看真实过程中硬盘如何读写数据。

当系统需要从磁盘读取数据时,系统将数据逻辑地址传给磁盘,磁盘的控制电路按照寻址逻辑将地址翻译成物理地址,确定要读取的数据在哪一个盘面,哪一个磁道,哪一扇区。为了读写这个扇区的数据需要做以下步骤:

  • 磁头沿着半径移动到要读取的扇区所在磁道上方,这段时间称为寻道时间 (Seek time),一般为 2~30ms,平均为 9ms 左右
  • 磁头到达磁道后,通过盘片旋转使得要读取的扇区旋转到磁头下方,这段时间叫旋转延迟时间 (Rotational latencytime)
  • 定位具体可读写的扇区后,如果是读数据,控制器计算此数据 ECC 码,然后将 ECC 码和磁盘记录的 ECC 码比较;如果是写数据,控制器计算此数据的 ECC 码与数据一起存储。

一个 7200 转 / 每分钟的硬盘,旋转一周所需时间 60*1000/7200 = 8.33ms,平均旋转延迟时间,假设为半圈也就是 4.17ms。平均寻道时间和平均旋转时间称为平均存取时间。

磁盘单次 IO 时间 = 寻道时间 + 旋转时间 + 存取时间

总结上面磁盘的读写可以知道数据的读写是按照从上到下,在盘面上从外向内进行。

局部性原理

因为硬盘的这种机械构造,所以磁盘本身的存取速度要比内存慢很多,再加上机械运动更加耗时。

预先读

所以为了提高硬盘的效率,减少磁盘 IO,磁盘往往不是严格的按需读取,而是每次都预先读取,即使只需要一个字节,磁盘也会从这个位置开始,顺序读取后面一定长度的数据放入内存。这样做的依据是计算机科学中著名的局部性原理,当一个数据被用到时,其附近的其他数据通常也会马上被用到。

页 (Page) 是许多计算机存储管理器的逻辑块,硬件和操作系统往往将主存和磁盘存储区域分割为连续的大小相等的块,每一个存储块称为一页(通常为 4k),主存和磁盘以页为单位交换数据。当程序要读取的数据不在主存中,会产生一个缺页异常,系统会向磁盘发出读盘信号,磁盘会找到数据的起始位置并向后连续读取一页或几页载入内存中,然后异常返回,程序继续运行。

延迟写

一般硬盘上都会带一个比较小的磁盘缓冲存储器,将要写的数据缓冲,进而减少磁头移动,再一次性写入。

保护磁盘的方法

减小震动

硬盘内部因为是机械结构,在磁头和盘片之间有一个很小的空隙,如果硬盘有震动或者抖动,那么就可能造成磁盘数据损毁,所以在硬盘通电后就尽量不要移动硬盘,并且要尽量减缓硬盘转动可能带来的共振。

防尘

机械硬盘的内部构造必须保证觉得无尘,一旦有小的灰尘进入硬盘密封层,和磁头与盘片发生碰撞就可能造成机械设备的损坏。

使用 UPS 不间断电源

另外也不要对正在运行的磁盘突然断电,用正常的方式关闭系统,等待系统将缓存数据写回磁盘,然后再断电。所以如果家里有 NAS,建议还是购入 UPS,以免家中停电或者跳闸时可能对数据造成损害。

存储与分区

介绍了硬盘物理的构成,现在回到操作系统软件层面,相信装过机的人一定知道分区,在安装系统的时候要给系统划分一个系统分区。那么硬件启动的时候引导然后在硬盘上对应的地方启动系统。那么这里就需要知道整个磁盘的第一个扇区。

每一块物理硬盘的第一个扇区记录了整块磁盘的重要信息,包括:

  • 主引导分区 (MBR, Master Boot Record),安装引导程序的地方,446bytes。系统开机时会去读取这个分区
  • 分区表 (Partition Table),记录整块硬盘分区,64bytes

以前在使用 Windows 的时候有一个不小的疑惑,一块硬盘只能够划分四个分区(主分区 + 扩展分区),原因就在这里,分区表只有 64 bytes 大小,最多只能容纳四个分区。但实际上 Windows 可以通过逻辑分区来划分更多的分区。

PMR vs SMR

再上面说了那么多原理之后,假如硬盘厂商要提高硬盘的容量会怎么做呢?数据是存放在盘片上的,而具体数据是存在扇区上的。所以很自然的会想到:

  • 增加盘片数量
  • 增加磁盘面积
  • 增加磁盘盘片上存储数据的密度

前两者会增加硬盘的体积和重量,而现在的硬盘标准是固定的,随意改变硬盘大小必然会引起问题。所以目前大部分的解决方案就是提高单个磁盘数据存储的密度。于是这个公司的硬件工程师就提出了各种各样的办法。

LMR

最早期磁性颗粒平铺在盘片上,磁感应的方向是水平的,这类技术被称为 LMR(Longitudinal magnetic recording, 水平磁性记录)。这种方式有一个缺点,盘片利用率不高,当磁力颗粒很小,相互靠近时,容易受到干扰,方向发生混乱。所以 LMR 时代,单盘存储的数据有限。

PMR

为了解决 LMR 容量的限制,工程师们又想出了让磁性颗粒和磁感应方向相对盘片垂直。这个就叫做 PMR(Perpendicular Magnetic Recordking, 垂直磁性记录)。

在 PMR 技术下,3.5 寸盘,单碟磁盘的容量可以达到 1TB 左右。

SMR

不过随着互联网发展人们要存储的东西越来越多,PMR 逐渐不够用了,所以硬件工程师又想出了 SMR(Shingled Magneting Recordking,叠瓦式磁记录技术)。

SMR 利用了磁道与磁道之间的距离,通常硬盘的磁道与磁道之间存在一个保护距离,保护不同磁道直接的磁性颗粒不造成干扰。另外一个现实情况便是,硬盘信息的读取和写入是两个不同的操作,读取磁头和写入磁头也是不一样的。现代硬盘读写的磁头不同,写入磁头是传统的磁感应磁头,比较宽,读取磁头是新型的 MR 磁头,比较窄,磁道在划分的时候,需要满足最宽的标准。但是写入磁头在工作的时候,实际上对于每一个磁道,写入的信息宽度和读取的宽度是一样的,那么,磁道的空间就造成了浪费。于是工程师想到,把这部分浪费的磁道重叠起来,和房屋的瓦片一样,写入的时候沿着每条磁道上方写入,中间留下一小段保护距离,然后接着写另一条磁道。

使用 SMR 技术的硬盘又被网友称为叠瓦盘。

smr hdd

在 SMR 技术的帮助下,磁盘存储的容量大大增加了,但是缺点也很明显。首先是磁盘信息密度高,转速不能太快。另外 SMR 硬盘,单纯读问题不大,但是如果要修改某个磁道上的数据就比较麻烦,磁道间隙小,磁头比较宽,修改相邻磁道数据必然会相互影响。

解决这个问题的方法就是,每重叠一部分磁道时,隔开一些,另外就是设置专用缓冲区,当修改磁道 2 数据时,把磁道 3 的数据先取出来放到缓冲区,等磁道 2 数据改完再将磁道 3 数据写回。

也正是因为这个原因,一般的 SMR 硬盘具有大缓存的特点,一般可以达到 256MB,而普通的硬盘 64MB 足够。因为这样特殊的设计,在修改大量数据时会比较慢,时间久了会对硬盘读写性能造成影响。

总结

相较于 PMR 硬盘,SMR 硬盘不适合用来当作系统盘或者需要频繁读写的硬盘来使用

  • 更适合当作仓储盘,用来备份数据
  • 冷数据存储盘

NAS 盘与普通盘的区别

NAS 盘和普通盘的本质区别在于 Time Limited Error Recovery,TLER 技术(希捷叫 ERC,ErrorRecovery Control)3

一块硬盘长时间运行过程中,可能会因为各种情况出现读写错误,并且运行时间越长,出现的可能性越大,但是出现错误后,硬盘不会因此而损坏,硬盘内部的控制器会尝试进行修复,转移,纠错等操作,这一过程根据修复的难度,会用时几秒到几百秒左右,在这期间,硬盘会处于一个停止响应的状态。

RAID 中,一旦发现一块硬盘在一定时间内无响应,就会认为硬盘损坏,剔除该硬盘。如果硬盘硬因为一个可恢复的读写错误进入无响应状态,而刚好这个硬盘处于一个 RAID 阵列,无响应时间一旦超过 8 秒的阈值,RAID 控制器自然会认为硬盘损坏,并开始一系列恢复操作。这时 TLER 就派上了用场,有 TLER 功能的硬盘将执行正常的错误恢复,但 7 秒后,会向 RAID 控制器发出错误消息,并将错误恢复任务推迟到稍后的时间。通过协调错误处理,硬盘驱动器不会从 RAID 阵列中删除,从而避免了整个 RAID 恢复、替换、重建和返回操作。也就是说有 TLER 功能的硬盘,在硬盘恢复期间,会每隔 7 秒向 raid 控制器报告一次”正常”从而阻止阵列的重建。

有 TLER 功能的 NAS 盘更加适合在 RAID 阵列中工作,TLER 不会减少读写时可能造成的错误,也不会加快错误恢复速度,但可以在纠错中保护未响应的硬盘不被 RAID 控制器因为超时而误判为硬盘损坏。

NAS 盘只有在 RAID 阵列中才能体现其价值。

总结

在看了硬盘的工作原理,再回到如何选购一块硬盘的主题上。相信到这里,再去看硬盘的配置信息,比如转速 5400 RPM,7200 RPM,缓存 64MB, 256MB ,使用的 PMR, 还是 SMR 技术,就比较清楚了,然后再根据自身的情况酌情选购即可。

reference


2020-03-25 hard-drive , computer , ssd , hdd , guide , data-storage

如何查找链到某个链接的页面

有的时候想要查看一个网页有多少其他的页面链接过来,这个搜索语法似乎在 Google 上没见过,平时用的比较多语法也就是用 site: 来查看某个站点中的关键字。

那有什么方法可以查看某一个页面有谁链接过来了呢?

Google Search Console

Google Search Console 中可以查看到:

Search Console > choose your property > Links > External links > Top linking sites

ahrefs

ahrefs 是一个逆向链接的索引,可以简单的查看一些,但如果要查看完整的报告则需要订阅。


2020-03-25 backlink , google , link , search-tip , tip , skill

Proxmox VE 设定直通硬盘

之前的文章讲了 Proxmox VE 的安装,以及在此基础上又安装了 OpenMediaVault,现在我的机器上一共三块硬盘,120G SSD 安装了系统,并作为默认的 lvm,放一些 ISO,以及存放一些系统盘,另外的 1T 准备做 Proxmox 相关的数据盘,而剩下的一块 4T 盘想要直通给 OpenMediaVault 做数据盘。所以就产生了这样的一个需求。

首先在设定之前,需要知道 Linux 下的硬盘都会以文件方式存放在 /dev/disk/by-id/ 目录下。

查看硬件设备

安装:

apt install lshw

查看:

lshw -class disk -class storage

在输出的一串中,找到想要直通的硬盘 Serial,这一步一般也可以通过 Proxmox 后台 Disk 来查看到。比如我的情况是第一块硬盘 /dev/sda 然后假设 Serial 是 WFN1XXXX.

那么过滤出该硬盘:

ls -al /dev/disk/by-id |grep WFN1XXXX

然后添加到具体 ID 的 KVM 虚拟机。

qm set 100 -scsi2 /dev/disk/by-id/ata-ST4000DM004-2CV104_WFN1XXXX

说明:

  • 这里 100 是我的 OpenMediaVault 虚拟机的 ID
  • 后面是硬盘的位置,这里的参数 -scsi2 表示的是使用 [[SCSI]] 的第二块硬盘,如果你要加多块硬盘,数字 2 需要往后加 -scsi3 这样。

如果要检查虚拟机 100 中已经添加的硬盘,可以在 Proxmox 后台,点击虚拟机 ID,然后在 Hardware 中看 Hard Disk。

pve-hard-disk-pass-through.png

检查是否配置成功

在上面添加到虚拟机之后,可以在 Proxmox 界面中查看,或者用命令:

grep "WFN" /etc/pve/qemu-server/100.conf

理论上应该输出 scsi2 然后后面是硬盘的位置及编号。

然后就能在 OpenMediaVault 中识别出该硬盘了。在 OpenMediaVault 中识别出硬盘之后就可以把这个硬盘加到联合硬盘池里面,扩展存储空间。

SCSI vs VIRTIO

上面 qm 命令中用了 -scsi2 这里指的是磁盘总线类型 (scsi) 和编号 (2),目前磁盘总线类型大致上有这么几种:

  • IDE (Integrated Drive Electronics, 电子集成驱动器) - Slow Write in the Guest System
  • SCSI (Small Computer System Interface, 小型计算机系统接口,用于计算机和设备比如硬盘,光驱,打印机等等的系统级接口和独立处理器标准) - Faster Write(as IDE) in Guest System
  • VIRTIO - Fastest Write (more that SCSI and IDE) in the Guest System, but only with extra Drivers (In Guest)

三种类型的对比:

reference


2020-03-22 proxmox , pve , virtual , linux , debian

OpenMediaVault 初始化设置

OpenMediaVault,是一个开源的基于 Debian Linux 的下一代网络附加存储 (NAS) 解决方案。

关于 NAS 系统的选择可以参考这篇文章.

默认用户名和密码

OpenMediaVault 安装后的 Web UI,默认的用户名和密码是:

admin
openmediavault

登陆后进行修改。

ssh 登录

Web UI 的用户名是 admin,但是 SSH 的用户名是 root

安装必要的 package

apt install dnsutils htop

镜像源

如果安装的时候没有选择国内的镜像源,可以手动进行修改:

vi /etc/apt/sources.list

然后使用如下配置:

deb https://mirrors.tuna.tsinghua.edu.cn/debian/ buster main contrib non-free
# deb-src https://mirrors.tuna.tsinghua.edu.cn/debian/ buster main contrib non-free
deb https://mirrors.tuna.tsinghua.edu.cn/debian/ buster-updates main contrib non-free
# deb-src https://mirrors.tuna.tsinghua.edu.cn/debian/ buster-updates main contrib non-free
deb https://mirrors.tuna.tsinghua.edu.cn/debian/ buster-backports main contrib non-free
# deb-src https://mirrors.tuna.tsinghua.edu.cn/debian/ buster-backports main contrib non-free
deb https://mirrors.tuna.tsinghua.edu.cn/debian-security buster/updates main contrib non-free
# deb-src https://mirrors.tuna.tsinghua.edu.cn/debian-security buster/updates main contrib non-fre

omv-extras

OMV Extras 是一系列的扩展插件,开启后有不少的功能增强。

安装:

wget -O - https://github.com/OpenMediaVault-Plugin-Developers/packages/raw/master/install | bash

来自:

修改终端 locale

sudo locale-gen "en_US.UTF-8"
sudo dpkg-reconfigure locales

然后选择

  • en_US.UTF-8 UTF-8
  • zh_CN.UTF-8 UTF-8

这样以后终端就可以显示中文了,同样的道理如果是其他语言找对应的选上即可。

docker mirror

Docker 的安装可以在 OpenMediaVault 的 Web UI 上完成,在安装 OMV Extras 后可以直接启用。国内网络环境不好的情况下,一定先替换上面的源再安装。

编辑 vi /etc/docker/daemon.json:

注意这里微软提供的 Docker 镜像已经限制只能 Azure 的机器使用了,如果使用 azk8s 会返回 403 错误:

Error response from daemon: error parsing HTTP 403 response body: invalid character '<' looking for beginning of value: "<html>\r\n<head><title>403 Forbidden</title></head>\r\n<body bgcolor=\"white\">\r\n<center><h1>403 Forbidden</h1></center>\r\n<hr><center>nginx/1.14.0 (Ubuntu)</center>\r\n</body>\r\n</html>\r\n"

自行替换成 aliyun 或者其他国内厂提供的 registry-mirrors 吧!

{
	"registry-mirrors": [
		"https://registry.azk8s.cn",
		"https://reg-mirror.qiniu.com"
	],
  "data-root": "/var/lib/docker"
}

重启:

/etc/init.d/docker restart

开启 sharedfolders

我全新安装的 OpenMediaVault 5.3.4 中,创建共享文件夹,系统不会自动在 sharedfolders 中创建文件夹,查了一下,发现是 OpenMediaVault 在 5.3.3-1 版本中将 sharedfolders 功能给禁用了,官方的说明 是可能造成不稳定。不过可以通过如下方法手工开启:

Disable the '/sharedfolder/<xyz>' feature by default on new
installations because it makes too much problems.
It can be enabled by setting the environment variable to
'OMV_SHAREDFOLDERS_DIR_ENABLED="YES"'. Finally run the command
'omv-salt stage run prepare' to apply the modified default values
and 'omv-salt deploy run systemd' to create the unit files.

但是我尝试一下之后发现创建共享文件后,sharedfolder 中依然没有,那我就只能手动 ln 了。(注意这里的地址需要换成你自己系统的地址)

ln -s /srv/dev-disk-by-label-storage/appdata /sharedfolders/appdata
ln -s /srv/dev-disk-by-label-storage/ruTorrent/ /sharedfolders/ruTorrent

Transmission

拉取镜像:

docker pull linuxserver/transmission

创建:

docker run -d \
  --name=transmission \
  -e PUID=1000 \
  -e PGID=1000 \
  -e TZ=Asia/Shanghai \
  -e USER=user \
  -e PASS=password \
  -e TRANSMISSION_WEB_HOME=/transmission-web-control/ \
  -p 9091:9091 \
  -p 51413:51413 \
  -p 51413:51413/udp \
  -v <path to data>:/config \
  -v <path to downloads>:/downloads \
  -v <path to watch folder>:/watch \
  --restart unless-stopped \
  linuxserver/transmission

ruTorrent

Pull 镜像:

docker pull linuxserver/rutorrent

创建:

docker run -d \
  --name=rutorrent \
  -e PUID=1000 \
  -e PGID=100 \
  -p 8080:80 \
  -p 5000:5000 \
  -p 51415:51413 \
  -p 6881:6881/udp \
  -v /sharedfolders/ruTorrent-config:/config \
  -v /sharedfolders/ruTorrent:/downloads \
  --restart unless-stopped \
  linuxserver/rutorrent

然后根据 这里 的说明改一下主题。

syncthing

docker run -d \
  --name=syncthing \
  -e PUID=1000 \
  -e PGID=1000 \
  -e TZ=Europe/London \
  -e UMASK_SET=<022> \
  -p 8384:8384 \
  -p 22000:22000 \
  -p 21027:21027/udp \
  -v </path/to/appdata/config>:/config \
  -v </path/to/data1>:/data1 \
  -v </path/to/data2>:/data2 \
  --restart unless-stopped \
  linuxserver/syncthing

Plex

docker pull linuxserver/plex

安装:

docker run -d \
  --name=plex \
  --net=host \
  -e PUID=1000 \
  -e PGID=1000 \
  -e VERSION=docker \
  -e PLEX_CLAIM= `#optional` \
  -v /path/to/library:/config \
  -v /path/to/tvseries:/tv \
  -v /path/to/movies:/movies \
  --restart unless-stopped \
  ghcr.io/linuxserver/plex

AdGuard Home

在 OpenMediaVault 上安装 AdGuard Home 的时候需要注意,OpenMediaVault 自身的 systemd-resolved 进程监听了 53 端口,和 AdGuard Home 产生了冲突。这个时候需要禁用系统 resolved 的 53 端口监听。

可以使用如下命令修改,也可以手动修改这两行:

sudo sed -i "s/^#Cache=yes/Cache=no/g" /etc/systemd/resolved.conf
sudo sed -i "s/^#DNSStubListener=yes/DNSStubListener=no/g" /etc/systemd/resolved.conf

然后重启进程 systemctl restart systemd-resolved

netstat 来查看 53 端口的占用情况。这个时候再用 Docker 启动 AdGuard Home:

docker run --name adguardhome -v /my/own/workdir:/opt/adguardhome/work -v /my/own/confdir:/opt/adguardhome/conf -p 53:53/tcp -p 53:53/udp -p 67:67/udp -p 68:68/tcp -p 68:68/udp -p 8080:80/tcp -p 443:443/tcp -p 853:853/tcp -p 3000:3000/tcp -d adguard/adguardhome

2020-03-22 openmediavault , nas , operating-system , os , system , linux , open-source

Proxmox 安装和设置

接触虚拟化的过程中慢慢的了解到了 [[Proxmox VE]],在此之前是看到很多人在用 [[ESXi]],一款 VMware 的商业化产品,个人授权是免费的,不过 Proxmox VE 是一个基于 Debian 的开源虚拟化系统,对于我这样的初学者,学习过程要比产品的稳定性来的重要,所以对我个人而言 Proxmox 是一个不错的选择。

Proxmox VE 全称是 Proxmox Virtual Environment 是一个开源的虚拟化解决方案,基于 QEMU/KVM 和 LXC。

Proxmox Virtual Environment is an open source server virtualization management solution based on QEMU/KVM and LXC. You can manage virtual machines, containers, highly available clusters, storage and networks with an integrated, easy-to-use web interface or via CLI. Proxmox VE code is licensed under the GNU Affero General Public License, version 3.

Proxmox VE,是一个开源的服务器虚拟化环境 Linux 发行版。Proxmox VE 基于 Debian,使用基于 Ubuntu 的定制内核,包含安装程序、网页控制台和命令行工具,并且向第三方工具提供了 REST API,在 Affero 通用公共许可证第三版下发行。

Proxmox VE 支持两类虚拟化技术:基于容器的 LXC(自 4.0 版开始,3.4 版及以前使用 OpenVZ 技术) 和硬件抽象层全虚拟化 KVM。

Proxmox 支持的虚拟化:

  • 基于内核的 [[KVM]] (Kernel-based Virtual Machine)
  • 基于容器的虚拟化技术 [[LXC]](Linux Containers)

准备工作

安装 Proxmox VE 之前有几件必须的东西需要准备:

  • Proxmox VE ISO 镜像,[[balenaEtcher]] 安装程序
  • 一个空 U 盘,容量不用太大,也不能小到 Proxmox ISO 文件都放不下
  • 主机 (64 位 CPU,至少 1G 内存,支持 KVM 的主板egrep '(vmx|svm)' /proc/cpuinfo),键盘和显示器(安装过程中需要,安装后就不用了)

安装

和安装其他 Linux 系统一样,先用 Etcher 将 Proxmox VE ISO 写入 U 盘。或者使用 dd 命令:

# dd bs=1M conv=fdatasync if=./proxmox-ve_*.iso of=/dev/XYZ

一定要注意 of 后别写错设备。如果不知道 dd 命令如何使用千万别复制粘贴上面命令。

将 U 盘插入主机,启动硬件,在 BIOS 中选择 U 盘启动,或者使用 F12 或者 F2,或者 DELETE 等等按键选择 U 盘启动。然后在 Proxmox 安装程序中下一步下一步既可,注意安装时输入的局域网 IP 地址,后面需要用该 IP 或者 (hostname) 来访问 Proxmox 的 Web 管理界面。

使用

安装完成后,重启系统,进入 Proxmox VE,等待屏幕显示黑色登录等待命令,可以使用局域网中其他电脑登录:

https://ip:8006

这里有两点需要注意,一定要用 https 访问,我用 http 访问是没有回应的,还重装了一遍,还以为有硬件故障检查了半天,甚至 root 登录进去重启了各种服务,最后发现必须要使用 https 登录;第二点就是输入安装时设置的 IP 地址,加上 8006 端口进行访问。

设置 host

PVE 官方要求设置 /etc/hosts 防止出现问题,可以手动执行 hostnamectl set-hostname pve 将本机 hostname 设置为 pve

127.0.0.1 localhost.localdomain localhost
your.ip pve.domain.com pve

设置更新源

Proxmox 源自于 Debian,所以 Proxmox 也可以用 apt 的包管理。但是 Proxmox 维护了一套自己的软件源,如果没有订阅企业授权,在 apt update 的时候会报错。所以需要注释掉企业的 source list:

vi /etc/apt/sources.list.d/pve-enterprise.list
然后用 # 注释掉其中的地址
# deb https://enterprise.proxmox.com/debian/pve buster pve-enterprise

然后添加非订阅的源,修改 vi /etc/apt/sources.list: 1

# PVE pve-no-subscription repository provided by proxmox.com,
# NOT recommended for production use
deb http://download.proxmox.com/debian/pve buster pve-no-subscription

或者直接创建一个新文件:

echo 'deb http://download.proxmox.com/debian/pve buster pve-no-subscription' >> /etc/apt/sources.list.d/pve-no-subscription.list

国内的 Proxmox VE 软件源镜像:2

deb https://mirrors.tuna.tsinghua.edu.cn/proxmox/debian buster pve-no-subscription

设置 Debian 国内镜像

Proxmox VE 基于 Debian 的软件源都可以替换成国内的镜像:3

deb https://mirrors.tuna.tsinghua.edu.cn/debian/ buster main contrib non-free
# deb-src https://mirrors.tuna.tsinghua.edu.cn/debian/ buster main contrib non-free
deb https://mirrors.tuna.tsinghua.edu.cn/debian/ buster-updates main contrib non-free
# deb-src https://mirrors.tuna.tsinghua.edu.cn/debian/ buster-updates main contrib non-free
deb https://mirrors.tuna.tsinghua.edu.cn/debian/ buster-backports main contrib non-free
# deb-src https://mirrors.tuna.tsinghua.edu.cn/debian/ buster-backports main contrib non-free
deb https://mirrors.tuna.tsinghua.edu.cn/debian-security buster/updates main contrib non-free
# deb-src https://mirrors.tuna.tsinghua.edu.cn/debian-security buster/updates main contrib non-free

然后更新 apt update,然后升级 apt upgrade

使用 sudo

生产环境中如果不想一直使用 root 账户来管理后台,可以参考官网 用户管理一章节的内容来添加账户,并分配给不同的角色。这一步可以先跳过,等后面部署真正用起来后再配置就行。

安装 sudo

apt install sudo

然后编辑 visudo:

einverne    ALL=(ALL:ALL) NOPASSWD:ALL

BBR

目前的Proxmox VE版本的linux内核版本比较新,已经包含了bbr模块了。

如果没有包含可以使用如下方法:

echo "net.core.default_qdisc=fq" >> /etc/sysctl.conf
echo "net.ipv4.tcp_congestion_control=bbr" >> /etc/sysctl.conf
sysctl -p
# 验证
lsmod | grep bbr

配置

经过上面的配置 Proxmox 已经处于一个可用的状态。

通过 ISO 镜像安装 Proxmox 后 Proxmox 会自动创建一个 pve 的 Volume Group,并在其上面创建 root, data 和 swap 三个逻辑卷。

默认情况下 Proxmox 会自动创建 local(pve) 和 local-lvm(pve) 这两个 Storage,分别用来存放镜像和磁盘:

  • local 是 Directory 类型,用来存放 VZDump backup file, ISO Images, Container template
  • local-lvm 是 LVM-Thin 类型,用来存放 Disk image, Container

上面两个存储是在 Proxmox 安装后自动创建的,使用 fdisk -l 来看,我的 Proxmox 是安装在了 /dev/sdc 这款 120G 的 SSD 上。

Storage

Proxmox 支持两类文件存储类型:

  • 本地 (ZFS, LVM, Linux 支持的任何文件系统)
  • 网络存储 (NFS, CIFS, iSCSI)

本地的存储类型肯定是最稳定的,但问题也就是空间大小有限制。但假如在万兆局域网中,网络传输造成的瓶颈就不存在了,那么可以创建网络存储,挂载其他设备,比如 NAS 上的文件系统。

建立 Directory

在 GUI 界面中 Disks -> Directory 新建,要注意这里只有没有任何数据,没有任何分区的硬盘才能在菜单中显示,然后看到创建的执行日志:

# /sbin/sgdisk -n1 -t1:8300 /dev/sda
The operation has completed successfully.
# /sbin/mkfs -t ext4 /dev/sda1
mke2fs 1.44.5 (15-Dec-2018)
Creating filesystem with 976754385 4k blocks and 244195328 inodes
Filesystem UUID: rrrrr317-3e7f-4352-bda6-xxxxccde13fb
Superblock backups stored on blocks:
	32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208,
	4096000, 7962624, 11239424, 20480000, 23887872, 71663616, 78675968,
	102400000, 214990848, 512000000, 550731776, 644972544

Allocating group tables:     0/29809 done
Writing inode tables:     0/29809 done
Creating journal (262144 blocks): done
Writing superblocks and filesystem accounting information:     0/29809 done

# /sbin/blkid /dev/sda1 -o export
Created symlink /etc/systemd/system/multi-user.target.wants/mnt-pve-sda.mount -> /etc/systemd/system/mnt-pve-sda.mount.
TASK OK

可以看到我创建的 Directory 在 /dev/sda 这款硬盘上,首先 Proxmox 用 sgdisk 创建了一个分区 sda1,然后格式化了该分区为 ext4(这是我在 UI 界面中选择的),最后创建了一个挂载点,Proxmox 中是用 systemd 来管理的,具体可看到硬盘被挂载在了 /mnt/pve/sda 这个地方。

设置 ISO Directory

点击左侧边栏 DataCenter 下默认的 pve 节点,然后在右侧找到 Disks -> Directory ,新建 Directory。

这个时候需要注意,只有当硬盘没有任何数据的时候,才会在这里的菜单中显示。我在安装的时候是用的一块已经划分了分区的 1T 硬盘,所以需要 ssh 到后台,用 fdisk /dev/sda 来将分区删掉才能显示。

设置虚拟机的目录 Volume Group

和 ISO 目录一样,ISO 目录用来存放 ISO 镜像,虚拟机目录则是真正划分给虚拟机用的分区。在 Disks 中选中 LVM,创建 Volume Group。

Benchmark

在安装成功的 Proxmox 系统中可以执行 pveperf 来检查一下 CPU 和其他硬件的性能。

创建 VM 以 OpenMediaVault 为例

右上角创建 Virtual Machine,这里以安装 OpenMediaVault 来举例子。在 OpenMediaVault 下载好镜像 ISO,并上传到 Proxmox 中 local(pve) 中。

General

创建虚拟机的第一步就是给虚拟机起一个名字。PVE 使用数字来标识虚拟机,Name 字段起一个标志性的名字。

OS

在操作系统页面中,在 Storage 中选择刚刚建立的 ISO storage 目录,然后选择刚刚上传的 OpenMediaVault ISO 文件。

默认 Guest OS 会自动识别出对应的版本,下一步即可。

System

默认即可。

Hard Disk

设置硬盘大小,这一块硬盘会划分给 OpenMediaVault 系统,因为 OpenMediaVault 安装后占用体积也非常小,划分 16G 磁盘空间就已经足够。

CPU

设置虚拟机可以使用的 CPU 核心数。

Type 选择 Host,可以提供最好的性能。

Memory

设置内存,OpenMediaVault 内存占用也非常少,动态的设定一个 1G 到 4G 的动态范围。

高级设置中可以设置动态的内存使用范围。

Network

默认

点击既可创建成功。

其他

安装及使用过程中的一些疑问和操作。

如何移除 Storage

在界面中通过如下来移除一个存储:

Datacenter -> Storage -> Remove 选中的内容。

不过需要注意的是如果 GUI 移除了 Storage 定义, mount 文件并不会被删除,如果想要删除 mount 文件,只能通过 SSH 登录后台进行。Proxmox 中每一个 mount 都是由 systemd 管理,可以看到类似如下这样的文件。

假如新建了一个 testxfs 的存储,想要删掉:

cat /etc/systemd/system/mnt-pve-testxfs.mount
[Install]
WantedBy=multi-user.target

[Mount]
Options=defaults
Type=xfs
What=/dev/disk/by-uuid/xxxx6149-ce8f-4e36-94c4-xxxxxxj33e72
Where=/mnt/pve/testxfs

[Unit]
Description=Mount storage 'testxfs' under /mnt/pve

如果想要彻底删除的话,用 rm 把这个文件也删除。4

systemctl disable mnt-pve-testdir.mount
umount /mnt/pve/testdir
rm /etc/systemd/system/mnt-pve-testdir.mount

如何选择存储磁盘格式

在创建磁盘的时候可以选择 Directory, ZFS, LVM, LVM-Thin 等等。

Proxmox Storage types

Directory

Directory 是最常见的文件格式,Proxmox 包括了 ext4,xfs 。更多的文件格式可以参考我之前的文章

Proxmox VE can use local directories or locally mounted shares for storage. A directory is a file level storage, so you can store any content type like virtual disk images, containers, templates, ISO images or backup files.

Directory 可以存储任何的类型。

LVM 和 LVM-Thin

LVM 是 Logical Volume Manager(逻辑卷管理)的简写,是 Linux 环境下对磁盘分区进行管理的一种机制

在 Proxmox 中 只有 LVM 有 Snapshot 快照功能,而 LVM-Thin 是没有的。相反如果建立了 LVM 分区,那么整个分区只能给虚拟机或者容器使用,其他文档是无法放进去的,LVM-Thin 则没有这个限制。5

ERROR 挂载 NFS

在我想挂载 NAS 上 NFS 时,Proxmox 给了这错误,至今无解,不清楚是 NFS 版本不兼容的原因还是其他。

create storage failed: error with cfs lock ‘file-storage_cfg’: storage ‘Network-Proxmox’ is not online (500)

虚拟化技术

简单总结。

OpenVZ

OpenVZ 基于 Linux 内核的操作系统级虚拟化技术。OpenVZ 允许物理服务器同时运行多个操作系统。目前正逐渐被 KVM 代替。

KVM

[[KVM]] 全称是 Kernel-based Virtual Machine,基于内核的虚拟机,

Xen

Xen 是开放源代码虚拟机监视器,由 XenProject 开发,经过十几年时间的发展,目前正逐渐被 KVM 代替。

LXC

[[LXC]] 名字来自于 Linux Containers 缩写,是操作系统级的虚拟化,LXC 是 Linux 内核容器功能的一个用户空间接口。

其他虚拟化系统

VMware ESXi

VMware ESXi 可以直接存取控制底层资源,有效的利用硬件。ESXi 是 VMware 推出的虚拟化系统,对个人的授权是免费的。

Hyper-V

Hyper-V 是以 Hypervisor 为基础的虚拟化技术。适用于 x64 位的 Windows 系统。

Further

  • Proxmox 提供的官方文档
  • Proxmox 官方 Wiki

reference


2020-03-21 proxmox , pve , virtual , virtual-machine

电子书

最近文章

  • 给网站加上实时聊天对话框 tawk.to 使用记录 tawk.to 是一个可以在网页上添加客户聊天对话框的应用。用户可以通过 tawk.to 泡泡快速地得到支持。
  • 下载 YouTube 视频方法总结 之前就简单地介绍过使用yt-dlp 来下载 YouTube 视频,yt-dlp 是自从 youtube-dl 不再更新之后有人接手开发的新工具。但这篇文章重点是在于下载 YouTube 视频,我会整理一下我目前了解的所有可视化,命令行,Telegram bot 等等工具。
  • Tailscale 出口节点功能配置流量出口 之前的文章中介绍过 Tailscale ,是一个功能非常强大的虚拟组网的工具,底层使用更高级的 [[WireGuard]] 协议进行通信。之前的文章中只简单的介绍了一下 Tailscale 的使用,但是过去的时间里面 Tailscale 又更新了很多的新特性,这篇文章就介绍其中的一个特性 Exit Nodes。
  • Porkbun 免费领取一年 app wiki 等域名 [[Porkbun]] 通常被人戏称为「猪肉包」,是一家新成立于美国俄勒冈州波特兰市的域名注册商,母公司是 Top Level Design,后者是 design, ink 和 wiki 三个顶级域名后缀的管理局。这家域名注册商虽然成立时间比较短,但是胜在价格实惠。短短几年时间就打开了知名度。
  • 《负动产时代》读书笔记 怎么知道的这一本书