Bitbucket Runner 配置

以前有介绍过 Github Runner 和 Gitlab Runner 的配置,现在再来介绍一下 Bitbucket Runner 的配置。

参考官方文档: https://support.atlassian.com/bitbucket-cloud/docs/runners/

添加 Runner

首先禁用 Linux 系统的 swap 功能。若不禁用 swap,在 runner 进行 builder 时会使用 swap 内存,可能会出现内存不足的错误。

1
sudo swapoff -sv

编辑 /etc/sysctl.conf 添加 vm.swappiness = 1 再重启系统。

接着在 Bitbucket 的设置界面添加 Runner,然后执行界面给出的命令。
然后在目标机器上执行命令:

1
2
3
4
5
6
7
8
9
docker run-it -d \
--name bitbucket-runner \
-v /var/run/docker.sock:/var/run/docker.sock \
-e ACCOUNT_UUID=<accountUuid> \
-e REPOSITORY_UUID=<repositoryUuid> \
-e RUNNER_UUID=<runnerUuid> \
-e OAUTH_CLIENT_ID=<OAuthClientId> \
-e OAUTH_CLIENT_SECRET=<OAuthClientSecret> \
wusuopu/bitbucket-pipelines-runner:1.512

使用 Runner

bitbucket.pipelines.yml 中的相关步骤配置 runs-on,如:

1
2
3
4
5
6
7
pipelines:
default:
- step:
runs-on:
- self.hosted
- linux.shell
script:

因为 runner 是以 linux-shell 的方式运行的,所以会有一些限制: https://support.atlassian.com/bitbucket-cloud/docs/set-up-runners-for-linux-shell/

记录在docker中运行whenever遇到的问题

最近在将一个 rails 的项目移到 docker 方式来部署。这个项目有用到了 whenever 来执行定时任务,这里记录一下在迁移过程中遇到的一些问题。

因为 whenever 是使用系统的 cron 来实现的定时任务,所以直接就在 docker image 内安装一个 cron 即可: apt-get install -y cron
然后尝试执行命令: whenever -i; crontab -l 看看定时任务都有设置正确。最后在容器启动的时候使用命令 service cron start 一并将 cron 也启动。

至此感觉事情很简单,一切都很顺利。然而过了两天客户反馈说是这两天的定时任务都没有执行。
定时任务没执行,那就是 cron 有问题。现在来开始排查问题。

先再安装 syslog: apt-get install -y rsyslog,将 cron 的日志保存下来,方便查找错误。
然后往 crontab 中随便添加一条任务,每分钟执行一次命令: date >> /tmp/date.log

结果1分钟之后 cron 的日志显示有报如下错误:

1
FAILED to open PAM security session (Cannot make/remove an entry for the specified session)

经过搜索知道在 docker 内是没有 session 的,所以 PAM set_loginuid 会失败。需要将 set_loginuid 这行注释掉:

1
sed -i '/^session\s\+required\s\+pam_loginuid.so/c\#session required pam_loginuid.so' /etc/pam.d/cron

重启 cron 之后,date >> /tmp/date.log 定时任务也有正常执行了。

到此感觉问题应该是解决了。然而又过了一天客户还是说定时任务没有执行。
看来还是存在问题的,还得接着排查。

whenever 的任务是定时执行一些 rake 任务,然而执行的结果没有任何的日志。
于是我就新添加了一条 crontab 任务,将 rake 命令的 stdout 和 stderr 重定向到日志文件中。
然后就发现其实是因为在执行 rake 命令时提示 rake 命令不存在,从而导致执行失败的。
看来就因为 PATH 环境变量的问题。

在启动 container 时是有设置了一些环境变量的,然而 cron 这个进程并没有继承这些变量。
所以现在就需要手动为 cron 再配置环境变量。在启动 cron 之前先执行命令:

1
2
3
4
rm /etc/environment
for variable_value in $(cat /proc/1/environ | sed 's/\x00/\n/g'); do
echo $variable_value >> /etc/environment
done

现在再测试一切就正常了。
至此问题终于是解决了,于是就记录一下方便以后查阅。

Gitlab Runner 配置

前一篇文章有介绍了 Github Runner 的配置,现在再来介绍一下 Gitlab Runner 的配置。

关于添加自己的机器,可参考 Gitlab 官方文档: https://docs.gitlab.com/runner/register/index.html

同样的,为了方便,我们使用 docker 来一键部署。首先到 gitlab 的 CI/CD 项目设置页面,然后查看当前项目的 runner 注册 token。
然后执行如下命令进行 runner 注册。

1
2
3
4
5
6
7
8
9
10
11
12
docker run --rm -it -v $PWD/tmp/gitlab-runner-config:/etc/gitlab-runner gitlab/gitlab-runner:alpine register
--non-interactive \
--url "https://gitlab.com/" \
--token "PROJECT_REGISTRATION_TOKEN" \
--executor "docker" \
--docker-image alpine:latest \
--docker-volumes /var/run/docker.sock:/var/run/docker.sock
--description "docker-runner" \
--tag-list "docker,linux" \
--run-untagged="true" \
--locked="false" \
--access-level="not_protected"

注意这里的 PROJECT_REGISTRATION_TOKEN 需要替换为对应的 token;
--run-untagged 要设为 true,才能运行所有的 job。否则就只会执行打了 tag 的 job 。
如果需要多个项目共享该 runner,那么 --locked 就设为 false;

注册成功之后会生成 ./tmp/gitlab-runner-config/config.toml 文件:

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
concurrent = 1
check_interval = 0

[session_server]
session_timeout = 1800

[[runners]]
name = "runner-docker-01"
url = "https://gitlab.com/"
token = "xxxxxxxxxxxxxxxxxxxx"
executor = "docker"
[runners.custom_build_dir]
[runners.cache]
[runners.cache.s3]
[runners.cache.gcs]
[runners.cache.azure]
[runners.docker]
host = "unix:///var/run/docker.sock"
tls_verify = false
image = "alpine"
privileged = true
disable_entrypoint_overwrite = false
oom_kill_disable = false
disable_cache = false
volumes = ["/var/run/docker.sock:/var/run/docker.sock", "/cache"]
shm_size = 0

如果更换服务器了,但是还想要继续使用该 runner 的配置,只需要保留该配置文件即可。

以上是 runner 注册成功,接下来就使用该配置文件来启动 runner 服务吧。
同样也是为了安全起见,我们使用 docker-in-docker 的方式来部署。
创建一个 docker-compose.yml 文件:

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

services:
dind:
image: docker:19.03-dind
privileged: true
# 使用国内docker镜像源
command: ["--registry-mirror", "https://hub-mirror.c.163.com"]
volumes:
- ./tmp/docker-lib:/var/lib/docker
- ./tmp/docker-run:/var/run

gitlab-runner:
image: gitlab/gitlab-runner:alpine
depends_on:
- dind
volumes:
- ./tmp/docker-run:/var/run
- ./tmp/gitlab-runner-config:/etc/gitlab-runner

然后执行命令 docker-compose up -d 启动服务即可。

Github Runner 配置

在之前的文章《Github Actions使用》有介绍了Github Actions的使用方法。
之前是直接的 Github 官方提供的 runner,来执行。不过官方提供的 runner 多少还是有些限制。
这次我们来尝试将自己的 server 配置成 runner 来执行 actions。

关于添加自己的机器,可参考 Github 官方文档: https://docs.github.com/en/free-pro-team@latest/actions/hosting-your-own-runners/adding-self-hosted-runners

在 github 中 runner 分为三个级别: repository, organization, enterprise。
其中 repository 级别的 runner 就只能在这个代码仓库下使用;
organization 和 enterprise 级别的 runner 可以在这个 organization 或者 enterprise 下的所有代码仓库中共享。

由于我是免费用户,这里我就以 organization 为例吧。另外为了方便我们就直接通过 docker 来运行。

参考官方文档,首先进入到 organization 的 actions 设置页面,然后选择添加一个 runner。没有 organization 的可以自己创建一个。
接着在自己的 server 上执行命令:

1
2
3
4
5
6
docker run -d \
-v /var/run/docker.sock:/var/run/docker.sock \
-e GH_REPOSITORY=xxxxxxxxxxxx \
-e GH_RUNNER_TOKEN=xxxxxxxxxxxxx \
-e GH_RUNNER_LABELS=label1,label2 \
wusuopu/github-actions-runner:2.273.6

其中 GH_REPOSITORY 就是设置页面上显示的 url 参数,GH_RUNNER_TOKEN 就是 token 参数。GH_RUNNER_LABELS 则根据自己的需要来为该 runner 设置标签。

至此,自己的 runner 就已经配置好了。不过这里我们是直接在这个 runerr 的 container 中操作 server 上的 docker 服务。这样其实是非常危险的,尤其是对于公有仓库来说。

为了安全起见,我们可以再运行一个 Docker-in-Docker 的服务,然后这个就只需要连接到该服务即可。
创建一个 docker-compose.yml 文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
version: "2"

services:
dind:
image: docker:19.03-dind
privileged: true
volumes:
- ./tmp/docker-lib:/var/lib/docker
- ./tmp/docker-run:/var/run

github-runner:
image: wusuopu/github-actions-runner:2.273.6
depends_on:
- dind
environment:
- GH_REPOSITORY=https://github.com/xxxx
- GH_RUNNER_TOKEN=xxxxxxxxxxxxx
- GH_RUNNER_LABELS=dind
volumes:
- ./tmp/docker-run:/var/run

然后执行命令 docker-compose up -d 启动服务即可。
如果之后 actions 任务太多处理不过来,可以将 runner 扩容,多增加几个 runner 实例: docker-compose scale github-runner=3

至此,我们自己的 runner 就配置好了。如果想要在 actions 中使用我们自己的 runner,则需要修改之前的配置文件 .github/workflows/main.yml。将 runs-on: ubuntu-latest 改为 runs-on: self-hosted

使用python编写帝国时代2修改器

之前的文章有介绍了《使用python编写游戏修改器》
最近怀旧一下,在玩《帝国时代2》,然后就尝试着再写一个修改器试试。

查找内存地址

首先用 Cheat Engine 来修改资源,以及查找资源的内存地址。注意这里的数据都要使用浮点数类型。
如图找到的食物内存地址是 0F2B93B0
age2_ce01

通过逐步分析得到以下指标的内存地址为:
木材地址 = 食物地址 + 4
石头地址 = 食物地址 + 8
黄金地址 = 食物地址 + 12
黄金地址 = 食物地址 + 12
人口上限地址 = 食物地址 + 16
当前人口地址 = 食物地址 + 44

如果想要实际无限人口,只需要修改 人口上限 和 当前人口 这两个数据即可。
这些地址都找到之后,然后就开始写代码,使用 Python 调用 WriteProcessMemory 来修改游戏的内存。
然而在打完这一局之后开启新的游戏时却发现这些地址全都变了。
每次开启新的游戏时都需要重新查找一遍地址内存,这个就有点麻烦了。

查找游戏基址

通过分析发现这些地址都全是动态地址,每次游戏时都不一样。根据仅记得的一点汇编知识知道,这些动态地址是通过基址加偏移地址得到的。所以现在一劳永逸的方法是找到基址地址。而基址是静态的。然后接下来逐步进行分析。

首先刚刚食物地址是0F2B93B0。游戏程序如果要从这个地址获取食物数据,那么就得在某个地方储存这个地址值。这里我们就先将这个地址称为食物地址指针。接着用 CE 查找一下 0F2B93B0 这个值,然后就找到了食物地址指针地址为 206221B8。如图:
age2_ce02
注意这里要用 16 进制的方式来查找这个地址值。如果用 C 语言代码的描述相当于:

1
2
3
int food_point = 0x206221B8       // 食物地址指针
int food_address = *food_point; // 食物地址指针 指向食物地址 0x0F2B93B0
int food = *food_point; // 从食物地址 0x0F2B93B0 得到食物的值

经过测试发现这个食物地址指针地址也是动态的。没办法了,只能继续往下找。现在来看看都有谁访问了这个地址。如图:
age2_ce03
age2_ce04
这里我们又得到了一个地址: 20622110 。再来看看是哪里记录了这个地址呢。如图:
age2_ce05
这里我们又找到了 007A5FEC 这个地址,运气不错。在 CE 中显示为绿色,表示它是一个静态地址。这表示它就是我们要找的基址了。

总结

现在来总结一下。使用 C 语言代码描述如下:

1
2
3
4
int base_addr = 0x007A5FEC;             // 游戏基址
int food_point = *base_addr + 0xA8; // 基址记录的值0x20622110 + 偏移地址0xA8 = 食物地址指针
int food_address = *food_point; // 得到食物地址
int food = *food_address; // 从食物地址 0x0F2B93B0 得到食物的值

最终修改的结果如图:
age2_ce06

上面修改器的完整源代码,如有需要可通过以下链接获取:
https://github.com/wusuopu/cheat_engine_age2

使用Vagrant和Docker搭建Kubernetes集群

在之前的文章《使用Vagrant在Ubuntu系统上搭建Kubernetes集群》介绍了使用 Vagrant 在 VirtualBox 中安装 Ubuntu 系统搭建 Kubernetes 集群。
因为 Vagrant 是支持 Docker 的,所以这篇文章就来尝试不再使用 VirtualBox 了,而是直接使用 Docker 来搭建 Kubernetes 集群。

安装依赖

需要先安装以下程序:

  • Vagrant
  • Docker
  • Kubectl

运行集群

因为是在本地学习 k8s,因此为了方便我就使用 Rancher 的 k3s 来进行安装。
下载 Vagrant 配置文件: https://github.com/wusuopu/kubernetes-vagrant-alpine

然后执行命令:

1
vagrant up --no-parallel --provision

这里启动 k3s 服务,并将 master node 的 /etc/rancher/k3s/k3s.yaml 文件内容复制到 host 系统上来,这样就可以直接在 host 系统中用 kubectl 来操作集群。

1
2
3
4
5
6
-> % k get node -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
alpine-02 Ready <none> 59m v1.17.4-k3s1 172.17.0.3 <none> Alpine Linux v3.11 4.9.184-linuxkit docker://19.3.8
alpine-01 Ready master 59m v1.17.4-k3s1 172.17.0.2 <none> Alpine Linux v3.11 4.9.184-linuxkit docker://19.3.8
alpine-03 Ready <none> 58m v1.17.4-k3s1 172.17.0.4 <none> Alpine Linux v3.11 4.9.184-linuxkit docker://19.3.8

这里集群的各个 node 都是一个 docker container。

1
2
3
4
5
-> % docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a91d13e2cca0 wusuopu/vagrant:k3s-alpine "dockerd-entrypoint.…" About an hour ago Up 35 minutes 2375-2376/tcp, 6443/tcp, 127.0.0.1:2201->22/tcp kubernetes-vagrant-alpine_alpine-03_1585887389
cce93873b666 wusuopu/vagrant:k3s-alpine "dockerd-entrypoint.…" About an hour ago Up 35 minutes 2375-2376/tcp, 6443/tcp, 127.0.0.1:2200->22/tcp kubernetes-vagrant-alpine_alpine-02_1585887382
d4844843ca3e wusuopu/vagrant:k3s-alpine "dockerd-entrypoint.…" About an hour ago Up 36 minutes 2375-2376/tcp, 0.0.0.0:6443->6443/tcp, 127.0.0.1:2222->22/tcp kubernetes-vagrant-alpine_alpine-01_1585887365

Github Actions使用

最近在看 Github Actions,相对一 Gitlab CI 来说,它的配置就没有那么直观了。

以下通过一个例子来说下 Github Actions 的用法。

在项目根目录下创建文件 .github/workflows/main.yml

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
name: CI

on:
# 仅在有以 'v' 开头的 tag push 时才会触发
push:
tags:
- v*

jobs:
build:
name: build docker image
runs-on: ubuntu-latest

steps:
# 切换到当前的 commit
- uses: actions/checkout@v2
with:
ref: ${{ github.ref }}
- name: build docker image
env:
canister_user: ${{ secrets.canister_user }}
canister_password: ${{ secrets.canister_password }}
docker_image_name: cloud.canister.io:5000/${{ github.repository }}
run: |
echo $GITHUB_WORKSPACE $GITHUB_REF
cd $GITHUB_WORKSPACE
docker build -t $docker_image_name:${GITHUB_REF##*/} .
docker login -u $canister_user -p $canister_password cloud.canister.io:5000
docker push $docker_image_name:${GITHUB_REF##*/}

以上的配置执行的操作是,当有新的 ‘v’ 开头的 tag push 时,则 build docker image 并 push 到 cloud.canister.io 的私有 docker registry 上。

这里 canister 的用户名和密码是通过 secrets 来配置的,在 github 的 repository -> Settings -> Secrets 页面。

参考: https://help.github.com/en/actions

使用Vagrant在Ubuntu系统上搭建Kubernetes集群

安装依赖

Vagrant

目前 Vagrant (https://www.vagrantup.com/downloads.html) 最新为 v2.2.6,Kubernetes 为 v1.16

Kubectl

下载最新版的 kubectl:

1
`curl -LO https://storage.googleapis.com/kubernetes-release/release/`curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt`/bin/linux/amd64/kubectl`

VirtualBox

需要下载 Vagrant 所兼容的版本( https://www.vagrantup.com/docs/virtualbox/ )。我是直接用 apt-get 安装 5.2 的版本。

1
apt-get install virtualbox virtualbox-guest-additions-iso

运行 ubuntu 单实例

创建 Vagrantfile 配置文件,这里在 virtualbox 内运行的是 Ubuntu 18.04。
若 Vagrant 的 Box 文件下载太慢,可先提前下载好:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
wget https://app.vagrantup.com/ubuntu/boxes/bionic64/versions/20191125.0.0/providers/virtualbox.box

cat > virtualbox.json <EOF
{
"name": "ubuntu/bionic64",
"versions": [
{
"version": "20191125.0.0",
"providers": [
{
"name": "virtualbox",
"url": "virtualbox.box"
}
]
}
]
}
EOF

vagrant box add ubuntu/bionic64 virtualbox.json

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
# -*- mode: ruby -*-
# vi: set ft=ruby :

$num_instances = 1
$instance_name_prefix = "ubuntu"
$vm_gui = false
$vm_memory = 1024
$vm_cpus = 1
$vb_cpuexecutioncap = 100
ip_prefix = '172.17.8.'

Vagrant.configure(2) do |config|
(1..$num_instances).each do |i|
config.vm.define vm_name = "%s-%02d" % [$instance_name_prefix, i] do |node|
node.vm.box = 'ubuntu/bionic64'
node.vm.box_version = "20191125.0.0"
node.vm.box_check_update = false
node.vm.hostname = vm_name
node.vm.synced_folder '.', '/vagrant', type: 'virtualbox'

ip = "#{ip_prefix}#{i+100}"
node.vm.network 'private_network', ip: ip
node.vm.provider :virtualbox do |vb|
vb.gui = $vm_gui
vb.memory = $vm_memory
vb.cpus = $vm_cpus
vb.customize ["modifyvm", :id, "--cpuexecutioncap", "#{$vb_cpuexecutioncap}"]
end
end
end
end

接着启动 ubuntu

1
vagrant up

登录 ubuntu 实例

1
vagrant ssh

至此 ubuntu 就是运行起来了。然后却只有一个 实例,但是在实际应用中可能是多个实例组成的集群。

运行 ubuntu 多实例

先停止刚刚的实例

1
vagrant halt

然后修改 Vagrantfile 文件,将 $num_instances 变量改为3。这里我就启动3个实例来组成集群。
接着启动这3个实例

1
vagrant up

查看实例状态

1
2
3
4
5
6
7
8
9
10
-> % vagrant status
Current machine states:

ubuntu-01 running (virtualbox)
ubuntu-02 running (virtualbox)
ubuntu-03 running (virtualbox)

This environment represents multiple VMs. The VMs are all listed
above with their current state. For more information about a specific
VM, run `vagrant status NAME`.

然后登录到其中的某个实例

1
vagrant ssh ubuntu-02

安装 Kubernetes

目前的3个 ubuntu 实例如下:

1
2
3
172.17.8.101 (ubuntu-01)    master
172.17.8.102 (ubuntu-02) worker1
172.17.8.103 (ubuntu-03) worker2

因为是在本地学习 k8s,因此为了方便我就使用 Rancher 的 k3s 来进行安装。
先分别在各个实例中安装 docker,参考: https://docs.docker.com/install/linux/docker-ce/ubuntu/

先安装 master node

1
2
vagrant ssh ubuntu-01
curl -sfL https://get.k3s.io | sh -

接着分别进入另外两个实例内安装 worker node,其中 K3S_TOKEN 的值来自 /var/lib/rancher/k3s/server/node-token 文件。

1
2
vagrant ssh ubuntu-02
curl -sfL https://get.k3s.io | K3S_URL=https://172.17.8.101:6443 K3S_TOKEN=XXX sh -

最后可以将 master node 的 /etc/rancher/k3s/k3s.yaml 文件内容复制到 host 系统上来,这样就可以直接在 host 系统中用 kubectl 来操作集群。

1
2
3
4
5
-> % k get nodes -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
ubuntu-03 Ready <none> 4m57s v1.16.3-k3s.2 172.17.8.103 <none> Ubuntu 18.04.3 LTS 4.15.0-70-generic docker://19.3.5
ubuntu-02 Ready <none> 7m25s v1.16.3-k3s.2 172.17.8.102 <none> Ubuntu 18.04.3 LTS 4.15.0-70-generic docker://19.3.5
ubuntu-01 Ready master 8m5s v1.16.3-k3s.2 172.17.8.101 <none> Ubuntu 18.04.3 LTS 4.15.0-70-generic docker://19.3.5

当前安装的 k3s 是 v1.0.0,k8s 是 v1.16.3

最后我将完整的配置已经上传到 github 上了。大家有需要可以直接执行如下命令即可:

1
2
3
git clone https://github.com/wusuopu/kubernetes-vagrant-ubuntu
cd kubernetes-vagrant-ubuntu
vagrant up

使用TypeScript开发Express应用

首先创建新项目

1
yarn init

然后安装 express

1
2
yarn add express
yarn add @types/express @types/node --dev

安装 TypeScript

1
yarn add --dev typescript

配置 webpack

这是最麻烦的一步。先安装 webpack:

1
2
yarn add --dev webpack webpack-cli webpack-node-externals ts-loader
yarn add --dev nodemon webpack-shell-plugin

添加 webpack.config.js:

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
const path = require('path');
const nodeExternals = require('webpack-node-externals');
const WebpackShellPlugin = require('webpack-shell-plugin');

const { NODE_ENV = 'production' } = process.env;
const rootPath = path.resolve(__dirname)

let plugins = []
if (NODE_ENV === 'development') {
plugins.push(new WebpackShellPlugin({
onBuildEnd: ['yarn run:dev']
}))
}

module.exports = {
entry: path.resolve(rootPath, './src/index.ts'),
mode: NODE_ENV,
target: 'node',
watch: NODE_ENV === 'development',
externals: [ nodeExternals() ],
output: {
path: path.resolve(rootPath, 'build', NODE_ENV === 'development' ? 'dev' : 'prod'),
filename: 'index.js'
},
resolve: {
extensions: ['.ts', '.js'],
},
plugins: plugins,
module: {
rules: [
{
test: /\.ts$/,
use: [
'ts-loader',
]
}
]
},
}

添加 tsconfig.json:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
"compilerOptions": {
"module": "commonjs",
"target": "es5",
"noImplicitAny": false,
"sourceMap": true,
"outDir": "build"
},
"exclude": [
"node_modules",
"build",
"config",
"release"
]
}

package.json 中添加相关命令:

1
2
3
4
5
6
"scripts": {
"start": "node build/prod/index.js",
"start:dev": "NODE_ENV=development node node_modules/webpack/bin/webpack.js --config webpack.config.js",
"build": "NODE_ENV=production node node_modules/webpack/bin/webpack.js --config webpack.config.js",
"run:dev": "NODE_ENV=development nodemon build/dev/index.js",
}

这样在开发过程只需要执行 yarn run start:dev 启动开发服务器即可,在代码有改动之后会自己重新 build 并重启服务。
开发完成之后执行 yarn build 进行打包发布。

使用 jest 进行测试(可选)

安装 jest:

1
yarn add -D jest @types/jest ts-jest supertest

添加 jest.config.js:

1
2
3
4
5
6
module.exports = {
testEnvironment: 'node',
transform: {
"^.+\\.ts$": "ts-jest"
},
};

相应的测试文件的文件名以 .test.ts 结尾。

然后在 package.json 中添加相关命令:

1
2
3
"scripts": {
"test": "jest"
}

最终项目目录结构如下:

1
2
3
4
5
6
7
8
9
10
.
├── jest.config.js
├── package.json
├── src
│ └── index.ts
├── tests
│ └── index.test.ts
├── tsconfig.json
├── webpack.config.js
└── yarn.lock

参考源代码: https://github.com/wusuopu/baidu-pan-cli

记录神舟战神 Z7M-KP7GZ 安装黑苹果过程

前言

现在这台 MacBook Air 差不多用了4年,因此打算换台新的电脑。目前需要一台有独显的电脑,一来是跑一些程序,二来是方便打游戏。
另外由于 macOS 已经用习惯了,不想再换其他系统。因此才考虑的安装黑苹果。通过两周的调研,别人给的经验是最好选择已经有人安装成功过的电脑型号,免得有问题自己折腾。
于是乎就选择了性价比比较高的神舟。最后安装完成之后,系统还有些小问题,不过基本也能用。对于要求比较高的建议还是白苹果吧。

准备

  • 一个8G以上的U盘,用于烧写系统镜像
  • 一个U盘,大小不限,只要启动WinPE就行
  • 一个usb鼠标,安装过程中触摸板用不了

因为我打算安装3个系统,我的硬盘分区如下:

1
2
3
4
5
6
7
8
9
10
11
12
128G SSD:
ESP 600M 用于EFI引导
EXT4 127G 用于安装ubuntu

1TB机械硬盘:
ESP 200M 用于EFI引导
MSR 128M
NTFS 100G Windows C
NTFS 100G Windows D
SWAP 16G Linux交换分区
EXFAT32 320G 用于多个系统之间分享文件
APFS 440G 安装黑苹果

在安装过程中需要用苹果的硬盘工具进行分区,如果硬盘上有文件的话需要先进行备份。

安装过程我是参考的黑果小兵博客: https://blog.daliansky.net/Lenovo-Xiaoxin-Air-13-macOS-Mojave-installation-tutorial.html

下载镜像 ( https://blog.daliansky.net/tags/%E9%95%9C%E5%83%8F/ ) 然后使用镜像烧写工具将镜像烧写到8G的U盘。这里我用的是 Etcher 这个工具。
参考别人的说法,10.14 的系统没有 Nvidia 的显卡驱动,10.13 的系统才有。不过我还是下载的 10.14.4 的系统镜像。

下载 Z7M-KP7GZ 的相关驱动: https://github.com/kirainmoe/hasee-z7-kp7gz-macos

安装步骤

启动电脑进入 BIOS 禁用 Secure Boot。然后通过U盘启动进入WinPE,先按照上面的硬盘分区计划对硬盘进行分区。如果你是整块硬盘只用于安装 macOS,则可以忽略这上步。
然后重启换另一个U盘启动进入 macOS 的安装界面。进入 Clover 后按 o 键在 Boot 项后面添加 nv_disable=1 参数。如图:

然后回车开始引导 macOS。等几分钟之后就进入了安装程序,依次选择语言、同意用户协议、选择安装硬盘。
这里可以打开硬盘工具,然后进行分区。建议使用 APFS 格式的分区。注意,如果原来硬盘上有数据的记得先备份。如图:

安装过程中会重启,重启之后进入 Clover 再选择使用对应的硬盘分区,选择”Boot macOS install from Mac”启动项,不要选择Preboot的启动项。

如果出现Kernel Panic错误,重启再来试一遍吧。

安装过程中啥都干不了,只能等了。差不多等半个小时就安装完成。接下来进入设置向导,选择地区、添加几号等操作。这个过程中触摸板用不了,所以需要外接鼠标。
最后安装完成,进入系统。

系统安装完成之后,接下来就是安装EFI。因为现在EFI文件还是U盘里,否则就只能每次启动时都需要通过U盘来引导了。
在前面使用硬盘工具进行分区时,它会在当前硬盘的开始位置创建一个200M的ESP分区。我们只需要将U盘中的EFI复制到这个分区里即可。

打开终端执行命令:

1
2
3
4
5
6
# 查找分区情况
diskutil list

# 分别挂载本地硬盘的EFI分区各u盘的EFI分区
sudo diskutil mount disk1s1
sudo diskutil mount disk3s1

然后将u盘中EFI目录下的所有文件复制到硬盘中的EFI目录。如果之前已经有安装过其他的系统,那么只需要将u盘中的 EFI/CLOVER 复制到硬盘中的 EFI 目录下即可

安装驱动

现在系统安装好了,EFI也安装好了。应该就可以正常地进入系统了。不过目前还有这些问题:

  • 触摸板用不了
  • WiFi、蓝牙用不了
  • 显卡用不了,不用使用外接显示器

然后我们再接着安装驱动文件。先挂载 ESP 分区,备份 EFI 目录,以免出错之后进不了系统时可以恢复。

删掉 /EFI/CLOVER 文件夹中的所有文件,然后将刚刚下载的所有驱动文件复制到 /EFI/CLOVER 目录下。
重启电脑然后执行里面的 optimize.sh 脚本,注意不要启动HiDPI。驱动安装好之后触摸板应该就能用了。

如果声卡不能使用的话,执行命令 kextstat -list-only | grep AppleALC 看看AppleALC.kext 驱动已正确加载。如果没有正确加载,请将其安装在 /Library/Extensions 下后执行命令 sudo kextcache -i / 重建缓存并重启。

接下来搞定无线网卡,如果不想折腾直接用有线了行。Z7M-KP7GZ用的是Intel的无线网卡,这个在 macOS 下是无解的。
其他折腾过的网友建议是换Broadcom的。如果要使用AirDrop或者Handoff,要求有蓝牙4.0LE,需要特定型号的博通网卡,比如博通BCM94322HMP(有带蓝牙和不带蓝牙版本的,注意挑选)。

于是我就在淘宝上买了块 BCM94350 WiFi、蓝牙二合一。然后拆机将网卡换上去。网卡在风扇的旁边。

结果一开机系统就崩溃了,进入不了登录界面。后来联系卖家,他们说这个只有 macOS 10.13 的驱动,没有 10.14 的。而我安装主正是 10.14 的系统。
欲哭无泪啊,折腾了两天,BCM94350网卡的驱动实在搞不定。最后只得再买了个支持黑苹果的USB无线网卡。
另外显卡驱动目前在 10.14 下也是无解的。如果要外接显示器的话,可能需要再购买带显卡的 type-C 设备。