我的技术笔记

记录技术历程

ssh

小米路由Mini,刷机为开发版且开启SSH

1
ssh root@192.168.31.1

确保密码正确 ssh 登录小米路由器密,如下图

提示文本

breed

访问breed,找到 xiaomi-mini 的固件,下载小米路由Mini的bread

通过 scp 将下载的文件通过 ssh 上传到小米路由器 /tmp

1
scp /Users/Apple/Downloads/breed-mt7620-xiaomi-mini.bin root@192.168.31.1:/tmp

通过 ssh 登录确保 /tmp/breed-mt7620-xiaomi-mini.bin 文件正确后,执行命令刷机

1
mtd -r write /tmp/breed-mt7620-xiaomi-mini.bin Bootloader

等待小米路由器重启,此时路由器还未刷入三方固件。只是完成了 breed 的刷机
需要进入 breed

1
2
3
拔掉电源
先用硬物顶住路由器reset键,再给路由器通电,等到路由器灯闪的时候(大概3秒即可)
松开reset键,此时蓝灯闪烁!

电脑上在浏览器中访问192.168.1.1,就进入 breed 控制台

breed 固件备份

进入 “Breed Web 恢复控制台”

1
2
3
选择 ”固件备份“
依次点击 EEPROM
依次点击 编程器固件

openwrt

下载 opwnwrt 本站 CDN

还是在 “Breed Web 恢复控制台”

1
2
3
4
选择 ”固件更新“ 
在 ”常规固件“ 的 “固件” 项 点击 "选择文件",选择你要刷机的 openwrt 固件
点击 “上传”,等待上传完成
点击 “更新”

不希望把时间,浪费在打包 APK 这个事情上。集成自动打包工具

安装 gitlab-runner

1
2
3
curl -L https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh | sudo bash

apt install gitlab-runner

注册 gitlab-runner

1
gitlab-runner register
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 实际操作如下
root@vm:/home/x# gitlab-runner register
Runtime platform arch=amd64 os=linux pid=208812 revision=4e1f20da version=13.4.0
Running in system-mode.

Please enter the gitlab-ci coordinator URL (e.g. https://gitlab.com/):
https://192.168.2.3:8080/
Please enter the gitlab-ci token for this runner:
ymfhzJQBxysj1xjfPftU
Please enter the gitlab-ci description for this runner:
[vm]: CI Android Docker
Please enter the gitlab-ci tags for this runner (comma separated):
build-test
Registering runner... succeeded runner=ymfhzJQB
Please enter the executor: ssh, virtualbox, docker+machine, custom, docker, docker-ssh, parallels, shell, docker-ssh+machine, kubernetes:
docker
Please enter the default Docker image (e.g. ruby:2.6):
jangrewe/gitlab-ci-android
Runner registered successfully. Feel free to start it, but if it's running already the config should be automatically reloaded!

部分 runner 常用命令

注册

1
gitlab-runner register

注销

1
gitlab-runner unregister

当前运行

1
gitlab-runner list

启动

1
gitlab-runner start

停止

1
gitlab-runner stop

重启

1
gitlab-runner restart

查询状态

1
gitlab-runner status

删除无效 runner

1
gitlab-runner verify --delete

更多参考

修改配置

配置文件 /etc/gitlab-runner/config.toml 手动添加配置 builds_dir 和 cache_dir

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# 默认配置
concurrent = 1
check_interval = 0

[session_server]
session_timeout = 1800

[[runners]]
name = "CI Android Docker"
url = "https://192.168.2.3:8080/"
token = "CsHtxdf8s4-GsfgyrTRa"
executor = "docker"
[runners.custom_build_dir]
[runners.cache]
[runners.cache.s3]
[runners.cache.gcs]
[runners.cache.azure]
[runners.docker]
tls_verify = false
image = "jangrewe/gitlab-ci-android"
privileged = false
disable_entrypoint_overwrite = false
oom_kill_disable = false
disable_cache = false
volumes = ["/cache"]
shm_size = 0


# 修改后配置
concurrent = 1
check_interval = 0

[session_server]
session_timeout = 1800

[[runners]]
name = "CI Android Docker"
url = "https://192.168.2.3:8080/"
token = "CsHtxdf8s4-GsfgyrTRa"
executor = "docker"
builds_dir = "/opt/gitlab-runner/builds"
cache_dir = "/opt/gitlab-runner/cache"
[runners.docker]
tls_verify = false
image = "jangrewe/gitlab-ci-android"
privileged = false
disable_entrypoint_overwrite = false
oom_kill_disable = false
disable_cache = false
volumes = ["/cache"]
pull_policy="if-not-present"
shm_size = 0

修改配置 快捷脚本

1
2
# 备份配置文件,防止脚本错误
cp /etc/gitlab-runner/config.toml /etc/gitlab-runner/config.toml.bak
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
# -*- coding: UTF-8 -*-
#!/usr/bin/env python
#
# 环 境:Python 3
#
# 快速修改 gitlab 环境配置
#

import os
import platform
import shutil
import toml
import requests
import hashlib
import zipfile

def getFileMd5(filePath):
with open(filePath,'rb') as f:
md5obj = hashlib.md5()
md5obj.update(f.read())
hash = md5obj.hexdigest()

return hash

def unzip_single(src, dest, password):
#解压单个文件到目标文件夹
if password:
password = password.encode()
zf = zipfile.ZipFile(src)
zf.extractall(path=dest, pwd=password)
zf.close()

def unzip_all(src, dest, password=None):
if not os.path.isdir(src):
unzip_single(src, dest, password)
else:
it = os.scandir(src)
for entry in it:
if entry.is_file() and os.path.splitext(entry.name)[1]=='.zip' :
unzip_single(entry.path, dest, password)

def verifyRes(targetDir,remoteRes):
returnValue = False
if not os.path.exists(targetDir):
os.makedirs(targetDir)

srcFile = os.path.join(targetDir,"{0}-{1}.zip".format(remoteRes["name"],remoteRes["md5"]))
hasFile = False
if os.path.exists(srcFile):
hashMd5 = getFileMd5(srcFile)
print("cached,Md5",hashMd5)
if hashMd5 == remoteRes["md5"] or hashMd5 == remoteRes["md5"].lower():
hasFile = True

if not hasFile :
# 全新下载
httpResponse = requests.get(remoteRes["url"])
hashMd5 = None
if httpResponse.status_code == requests.codes.ok:
with open(srcFile,"wb") as f:
f.write(httpResponse.content)
hashMd5 = getFileMd5(srcFile)
print("new,Md5",hashMd5)
if hashMd5 == remoteRes["md5"] or hashMd5 == remoteRes["md5"].lower():
hasFile = True
if hasFile and zipfile.is_zipfile(srcFile) :
unzip_all(srcFile,targetDir)
returnValue = True
print("解压成功",srcFile)
return returnValue


if __name__ == '__main__':

dir = os.path.abspath(os.path.dirname(__file__))

source = None
osName = platform.system()
if osName == "Windows":
# 测试代码
source = os.path.join(dir,"gitlab-runner-config.toml")
elif osName == "Linux":
source = "/etc/gitlab-runner/config.toml"

if source is None:
print("Source config is none")
exit(1)
elif not os.access(source, os.F_OK):
print("Source config not exist")
exit(1)
elif not os.access(source, os.R_OK):
print("Source config can't read")
exit(1)
elif not os.access(source, os.W_OK):
print("Source config can't write")
exit(1)

target = os.path.join(dir,"config.toml")

# print("{0}".format(dir))

try:
shutil.copyfile(source, target)
except IOError as e:
print("Unable to copy file. %s" % e)
exit(1)
except:
print("Unexpected error:", sys.exc_info())
exit(1)

targetRunnerDefaultName = "android-runner-book"

targetRunnerName = input("Enter target runner name ({0}): ".format(targetRunnerDefaultName))
if len(targetRunnerName) == 0 :
targetRunnerName = targetRunnerDefaultName


if os.path.exists(target) :
hasChanged = False
configs = toml.load(target)

hostGradleHomeDir = None
hostAndroidSdkDir = None
if osName == "Windows":
# 测试代码
hostGradleHomeDir = os.path.join(dir,"gradle-home")
hostAndroidSdkDir = os.path.join(dir,"android-sdk")
elif osName == "Linux":
hostGradleHomeDir = "/opt/gitlab-runner/gradle-home"
hostAndroidSdkDir = "/opt/gitlab-runner/android-sdk"

# 测试代码
# shutil.rmtree(hostGradleHomeDir)
remoteGradleRes = {"url":"https://192.168.2.25:456/gradle-5.6.4-6.1.1.zip","md5":"A8CDFB46BE21A98EBFFAC9174276CF47","name":"xGradle-5.6.4-6.1.1"}
remoteAndroidSdkRes = {"url":"https://192.168.2.25:456/sdk-29.0.3.zip","md5":"BFA11A9E09C5B7525EFDD9627B2604FE","name":"xAndroidSdk"}
# remoteAndroidSdkRes = {"url":"https://192.168.2.25:456/sdk-29.0.3-with-ndk-21.0.3.zip","md5":"4D6DB607F10361C5EA2444CF137B446C","name":"xAndroidSdkWithNDK"}
hasLocalGradleRes = False
hasLocalAndroidSdkRes = False

for runnerConfig in configs["runners"]:
if runnerConfig["name"] == targetRunnerName:
# print(runnerConfig)
hasChanged = True
# 编译运行目录
runnerConfig["builds_dir"] = "/opt/gitlab-runner/builds"
runnerConfig["cache_dir"] = "/opt/gitlab-runner/cache"
# 禁用 CI 配置.自定义目录
runnerConfig["custom_build_dir"]["enabled"] = False

if "cache" in runnerConfig :
# 'cache': {'s3': {}, 'gcs': {}, 'azure': {}}
del runnerConfig["cache"]

if runnerConfig["executor"] == "docker" and "docker" in runnerConfig:
dockerConfig = runnerConfig["docker"]
runnerDockerVolumes = None
if "volumes" not in dockerConfig :
runnerDockerVolumes = []
else:
runnerDockerVolumes = dockerConfig["volumes"]
# 追加补充挂载 Host 主机目录到 gitlab-runner 的 docker 配置
volumeOfGradle = "{0}:/android/gradle:rw".format(hostGradleHomeDir)
if volumeOfGradle not in runnerDockerVolumes:
runnerDockerVolumes.append(volumeOfGradle)
hasLocalGradleRes = False
else:
hasLocalGradleRes = True

volumeOfAndroidSdk = "{0}:/android/sdk:rw".format(hostAndroidSdkDir)
if volumeOfAndroidSdk not in runnerDockerVolumes:
runnerDockerVolumes.append(volumeOfAndroidSdk)
hasLocalAndroidSdkRes = False
else:
hasLocalAndroidSdkRes = True
# print(runnerDockerVolumes)

if not hasLocalGradleRes:
hasLocalGradleRes=verifyRes(hostGradleHomeDir,remoteGradleRes)
if not hasLocalAndroidSdkRes:
hasLocalAndroidSdkRes=verifyRes(hostAndroidSdkDir,remoteAndroidSdkRes)

if hasChanged :
with open(target, 'w') as f:
r = toml.dump(configs, f)
# print(r)
print("配置已更新到:",target)

转载来源

Convert PEM to DER

1
openssl x509 -outform der -in certificate.pem -out certificate.der

Convert PEM to P7B

1
openssl crl2pkcs7 -nocrl -certfile certificate.cer -out certificate.p7b -certfile CACert.cer

Convert PEM to PFX

1
openssl pkcs12 -export -out certificate.pfx -in fullchain.pem -inkey privkey.pem

Convert DER to PEM

1
openssl x509 -inform der -in certificate.cer -out certificate.pem

Convert P7B to PEM

1
openssl pkcs7 -print_certs -in certificate.p7b -out certificate.cer

Convert P7B to PFX

1
2
3
4
openssl pkcs7 -print_certs -in certificate.p7b -out certificate.cer


openssl pkcs12 -export -in certificate.cer -inkey privateKey.key -out certificate.pfx -certfile CACert.cer

Convert PFX to PEM

1
openssl pkcs12 -in certificate.pfx -out certificate.cer -nodes

Docker 初始化部署

获取 docker jenkins 镜像

1
2
3
4
5
# 长期支持版本
docker pull jenkins/jenkins:lts

# 最新版本
docker pull jenkins/jenkins

初始 参数解释

docker 环境 目录 /var/jenkins_home 映射宿主目录 ~/jenkins
docker 环境 端口 8080 映射宿主端口 8002

1
2
3
4
5
# 后台方式运行
docker run -d -p 8002:8080 -v ~/jenkins:/var/jenkins_home --name jenkins --restart=always jenkins/jenkins

# 查看容器日志
docker logs -f jenkins

发现错误日志

1
2
touch: cannot touch '/var/jenkins_home/xxxx.log': Permission denied
Can not write to /var/jenkins_home/xxxx.log. Wrong volume permissions?

需要在 宿主 对目录授权 ~/jenkins

1
2
3
4
5
# 开启目录权限
sudo chmod a+rwx ~/jenkins

# 开启docker挂载权限
sudo chmod a+rw /var/run/docker.sock

Docker 中更新 jenkins

宿主下载 jenkins.war 目录 ~/jenkins,进入 docker shell

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 普通用户身份 进入容器 shell 其中 861b 为容器Id 861be1055500 的前4位,支持模糊查询
docker exec -it 861b /bin/bash

# root 身份 进入容器 shell 其中 861b 为容器Id 861be1055500 的前4位,支持模糊查询
docker exec -it -u root 861b /bin/bash

# 替换后
cp /var/jenkins_home/jenkins.war /usr/share/jenkins/jenkins.war
exit

# 重启容器
docker restart 861b

#下载 Android SDK 工具 并解压到 android.sdk
wget -O sdk.zip https://dl.google.com/android/repository/commandlinetools-linux-6609375_latest.zip && unzip sdk.zip -d android.sdk && rm sdk.zip

Hello,World

Docker 允许你在容器内运行应用程序, 使用 docker run 命令来在容器内运行一个应用程序。

eg:使用 Ubuntu 20.04 镜像, 输出 Hello World

1
docker run ubuntu:20.04 /bin/echo "Hello World From Ubuntu:20.04"

常用命令

查看容器

1
docker ps -a

关闭所有正在运行的容器

1
docker kill $(docker ps -a -q)

删除指定容器

1
docker rm -f 容器ID

清理所有 处于中止状态的容器

1
docker container prune

删除所有已经停止的容器

1
docker rm $(docker ps -a -q)

意外情况.删除容器。没能删除成功,出现 “Removal In Progress”

1
2
3
4
5
6
7
8
9
10
11
# 进入容器目录
cd /var/lib/docker/containers

# 找到上一步找到的hash值开头的文件夹,小心谨慎的删掉它
rm -rf xxxxxxxxxxxxxxxxxxxxxxxxxxxxx

# 重启服务
systemctl restart docker

# 核对检查
docker ps -a

删除所有未打 dangling 标签的镜像

1
docker rmi $(docker images -q -f dangling=true)

查看镜像

1
docker images

删除所有镜像

1
docker rmi $(docker images -q)

Dockerfile

1
2
# 通过当前目录下的 Dockerfile 创建镜像 xxx
docker build -t xxx .
0%