我的技术笔记

记录技术历程

不希望把时间,浪费在打包 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 .

初识 Docker

准备

查看 Ubuntu 是32位的还是64位的

1
getconf LONG_BIT

系统信息

1
lsb_release -a

查看操作系统架构

1
uname -a

安装

添加 Docker 官方 GPG KEY

1
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
国内阿里云版
1
sudo curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | apt-key add -

验证 KEY 的指纹

1
2
3
4
5
6
7
sudo apt-key fingerprint 0EBFCD88

# 输出为:
pub rsa4096 2017-02-22 [SCEA]
9DC8 5822 9FC7 DD38 854A E2D8 8D81 803C 0EBF CD88
uid [ 未知 ] Docker Release (CE deb) <[email protected]>
sub rsa4096 2017-02-22 [S]

添加稳定版 repository

1
2
3
4
sudo add-apt-repository \
"deb [arch=amd64] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) \
stable"
国内阿里云版
1
2
3
4
sudo add-apt-repository \
"deb [arch=amd64] https://mirrors.aliyun.com/docker-ce/linux/ubuntu \
$(lsb_release -cs) \
stable"

更新

1
sudo apt-get update

安装最新版本的 Docker ce 和 Containerd

1
sudo apt-get install docker-ce docker-ce-cli containerd.io

安装指定版本的 Docker ce 和 Containerd,先查看可获取的版本

1
apt-cache madison docker-ce

安装指定版本

1
sudo apt-get install docker-ce=<VERSION_STRING> docker-ce-cli=<VERSION_STRING> containerd.io

验证安装版本

1
docker --version

用户授权

将非root用户加入docker组,以允许免sudo执行docker

1
sudo gpasswd -a 用户名 docker

重启服务并刷新 docker组成员

1
2
3
sudo service docker restart

newgrp - docker

设置开机启动 Docker-ce

安装成功后默认已设置并启动,可忽略

1
2
sudo systemctl enable docker
sudo systemctl start docker

升级版本

安装上述流程,安装新版本即可

卸载

方案1

1
sudo apt-get remove docker docker-engine docker.io containerd runc

/var/lib/docker 的内容,包括镜像、容器、卷和网络,可以保留也可以删除。

但仍能看到docker版本

1
docker --version

方案2

1
2
3
sudo apt-get purge docker
sudo apt-get purge docker-ce
sudo apt-get remove -y docker-*

慎重,不要误删!!!包括镜像、容器、卷和网络

1
sudo rm -rf /var/lib/docker

会删除软件包而保留软件的配置文件

1
apt-get remove 

会同时清除软件包和软件的配置文件

1
apt-get purge

Docker 镜像加速

修改配置文件 /etc/docker/daemon.json 即可

1
sudo vim /etc/docker/daemon.json

加载重启docker

1
2
sudo systemctl daemon-reload
sudo systemctl restart docker

查看是否成功

1
docker info

查看镜像列表

1
docker images

删除镜像

1
2
3
4
docker rmi xxxx

# 强制删除
docker rmi -f xxxxx

容器列表

1
docker ps -a 

进入容器 bash

1
2
3
4
5
6
7


# attach 进入 容器
docker attach xxxx

# exec 进入一个已经在运行的容器
docker exec -i -t xxxx /bin/bash

删除容器

1
2
3
4
5
6
docker container rm -f xxx

# -f, --force 是够强制终止并删除一个运行中的容器;
# --help 帮助信息;
# -l, --link 删除容器的链接,但是保留容器;
# -v, --volumes 删除容器挂载的数据卷。
0%