Alpine自托管Git服务器-Gitea版

概览:

简介

使用 Docker 容器技术,快速搭建 Git 服务器,该教程主要使用 Gitea 搭建 Git 服务器。并使用 Nginx 进行代理,支持 HTTPS 加密,最后可选配置Act Runner;

节点信息

alpine base server

OS:Alpine Linux v3.20

  • Web Nginx Entry
  • Main Git Server Entry

初始化

基本配置

启用 community 源: vi /etc/apk/repositories

1
2
3
#/media/cdrom/apks
https://mirrors.ustc.edu.cn/alpine/v3.20/main
https://mirrors.ustc.edu.cn/alpine/v3.20/community

添加timezone配置:Asia/Shanghai

apk add vim neofetch

1
2
3
4
5
6
7
8
9
10
11
12
base:~# vi /etc/timezone
base:~# apk add vim neofetch
fetch https://mirrors.ustc.edu.cn/alpine/v3.20/main/x86_64/APKINDEX.tar.gz
fetch https://mirrors.ustc.edu.cn/alpine/v3.20/community/x86_64/APKINDEX.tar.gz
(1/5) Installing bash (5.2.26-r0)
Executing bash-5.2.26-r0.post-install
(2/5) Installing neofetch (7.1.0-r1)
(3/5) Installing vim-common (9.1.0707-r0)
(4/5) Installing xxd (9.1.0707-r0)
(5/5) Installing vim (9.1.0707-r0)
Executing busybox-1.36.1-r29.trigger
OK: 526 MiB in 111 packages

qemu-guest-agent (可选)

如果是安装在 qemu 虚拟化技术的环境,可以安装此工具,便于管理;

1
2
3
4
5
6
7
8
9
base:~# apk add qemu-guest-agent
(1/4) Installing numactl (2.0.18-r0)
(2/4) Installing liburing (2.6-r0)
(3/4) Installing qemu-guest-agent (9.0.2-r0)
(4/4) Installing qemu-guest-agent-openrc (9.0.2-r0)
Executing busybox-1.36.1-r29.trigger
OK: 492 MiB in 106 packages
base:~# rc-update add qemu-guest-agent
* service qemu-guest-agent added to runlevel default

Docker

安装 docker

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
base:~# apk add docker
fetch https://mirrors.ustc.edu.cn/alpine/v3.20/main/x86_64/APKINDEX.tar.gz
fetch https://mirrors.ustc.edu.cn/alpine/v3.20/community/x86_64/APKINDEX.tar.gz
(1/22) Installing ca-certificates (20240705-r0)
(2/22) Installing libseccomp (2.5.5-r1)
(3/22) Installing runc (1.1.14-r0)
(4/22) Installing containerd (1.7.17-r2)
(5/22) Installing libffi (3.4.6-r0)
(6/22) Installing libintl (0.22.5-r0)
(7/22) Installing libmount (2.40.1-r1)
(8/22) Installing pcre2 (10.43-r0)
(9/22) Installing glib (2.80.5-r0)
(10/22) Installing log_proxy (0.7.2-r0)
(11/22) Installing containerd-openrc (1.7.17-r2)
(12/22) Installing libmnl (1.0.5-r2)
(13/22) Installing libnftnl (1.2.6-r0)
(14/22) Installing libxtables (1.8.10-r3)
(15/22) Installing iptables (1.8.10-r3)
(16/22) Installing iptables-openrc (1.8.10-r3)
(17/22) Installing tini-static (0.19.0-r3)
(18/22) Installing docker-engine (26.1.5-r0)
Executing docker-engine-26.1.5-r0.pre-install
(19/22) Installing docker-openrc (26.1.5-r0)
(20/22) Installing docker-cli (26.1.5-r0)
(21/22) Installing docker-cli-buildx (0.14.0-r3)
(22/22) Installing docker (26.1.5-r0)
Executing busybox-1.36.1-r29.trigger
Executing ca-certificates-20240705-r0.trigger
Executing glib-2.80.5-r0.trigger
OK: 419 MiB in 78 packages

docker 配置

1
2
3
4
5
6
7
8
9
10
base:~# mkdir /etc/docker
base:~# vi /etc/docker/daemon.json
base:~# cat /etc/docker/daemon.json
{
"experimental": false,
"ipv6": false,
"icc": false,
"no-new-privileges": false,
"registry-mirrors": ["https://docker.1panel.live"]
}

启动 docker

1
2
3
4
5
6
7
8
9
10
11
12
13
14
base:~# rc-update add docker default
* service docker added to runlevel default
base:~# service docker start
* Caching service dependencies ... [ ok ]
* /var/log/docker.log: creating file
* /var/log/docker.log: correcting owner
* Starting Docker Daemon ... [ ok ]
base:~# addgroup ${USER} docker
base:~# rc-update add cgroups
* service cgroups added to runlevel default
base:~# apk add docker-cli-compose
(1/1) Installing docker-cli-compose (2.27.0-r3)
Executing busybox-1.36.1-r29.trigger
OK: 478 MiB in 79 packages
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
base:~# docker info
Client:
Version: 26.1.5
Context: default
Debug Mode: false
Plugins:
buildx: Docker Buildx (Docker Inc.)
Version: v0.14.0
Path: /usr/libexec/docker/cli-plugins/docker-buildx
compose: Docker Compose (Docker Inc.)
Version: v2.27.0
Path: /usr/libexec/docker/cli-plugins/docker-compose

Server:
Containers: 0
Running: 0
Paused: 0
Stopped: 0
Images: 0
Server Version: 26.1.5
Storage Driver: overlay2
Backing Filesystem: extfs
Supports d_type: true
Using metacopy: false
Native Overlay Diff: true
userxattr: false
Logging Driver: json-file
Cgroup Driver: cgroupfs
Cgroup Version: 2
Plugins:
Volume: local
Network: bridge host ipvlan macvlan null overlay
Log: awslogs fluentd gcplogs gelf journald json-file local splunk syslog
Swarm: inactive
Runtimes: io.containerd.runc.v2 runc
Default Runtime: runc
Init Binary: docker-init
containerd version: 3a4de459a68952ffb703bbe7f2290861a75b6b67
runc version: 2c9f5602f0ba3d9da1c2596322dfc4e156844890
init version:
Security Options:
seccomp
Profile: builtin
cgroupns
Kernel Version: 6.6.63-0-lts
Operating System: Alpine Linux v3.20
OSType: linux
Architecture: x86_64
CPUs: 4
Total Memory: 7.767GiB
Name: base
ID: e6939946-c6d6-4943-b17e-1fe1de7718aa
Docker Root Dir: /var/lib/docker
Debug Mode: false
Experimental: false
Insecure Registries:
127.0.0.0/8
Registry Mirrors:
https://docker.1panel.live/
Live Restore Enabled: false

安装镜像

1
2
3
4
5
6
7
8
9
10
11
12
13
base:~# docker pull nginx:alpine
alpine: Pulling from library/nginx
da9db072f522: Pull complete
e10e486de1ab: Pull complete
af9c0e53c5a4: Pull complete
b2eb2b8af93a: Pull complete
e351ee5ec3d4: Pull complete
fbbf7d28be71: Pull complete
471412c08d15: Pull complete
a2eb5282fbec: Pull complete
Digest: sha256:5acf10cd305853dc2271e3c818d342f3aeb3688b1256ab8f035fda04b91ed303
Status: Downloaded newer image for nginx:alpine
docker.io/library/nginx:alpine

开启 sawrm

1
2
3
4
5
6
7
8
9
10
11
base:~# docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx alpine 91ca84b4f577 2 days ago 52.5MB
base:~# docker swarm init
Swarm initialized: current node (zkz4753ejmuuqr0jpzsyymk6j) is now a manager.

To add a worker to this swarm, run the following command:

docker swarm join --token SWMTKN-1-5b6dlaw5y8kxcwp1xr3rg2fvtv0c3m3jfrtf1b3jwhfm8auq8h-5xhgfslrialw4sst1n187y8rq 192.168.6.2:2377

To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.

安装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
base:~# apk add acme.sh
(1/11) Installing brotli-libs (1.1.0-r2)
(2/11) Installing c-ares (1.33.1-r0)
(3/11) Installing libunistring (1.2-r0)
(4/11) Installing libidn2 (2.3.7-r0)
(5/11) Installing nghttp2-libs (1.62.1-r0)
(6/11) Installing libpsl (0.21.5-r1)
(7/11) Installing libcurl (8.11.0-r2)
(8/11) Installing curl (8.11.0-r2)
(9/11) Installing readline (8.2.10-r0)
(10/11) Installing socat (1.8.0.0-r0)
(11/11) Installing acme.sh (3.0.7-r0)
Executing busybox-1.36.1-r29.trigger
OK: 484 MiB in 90 packages

申请证书

1
2
3
4
acme.sh --register-account -m email=acme@guzal.cc #curl https://get.acme.sh | sh -s email=acme@guzal.cc
acme.sh --issue -d guzal.cc -d *.guzal.cc --dns --yes-I-know-dns-manual-mode-enough-go-ahead-please
# 注意,分开添加记录,每次添加完一个都需要重新renew一次
acme.sh --renew -d guzal.cc -d *.guzal.cc --dns --yes-I-know-dns-manual-mode-enough-go-ahead-please
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
base:~# acme.sh --register-account -m email=acme@guzal.cc
[Fri Nov 29 18:47:49 CST 2024] Create account key ok.
[Fri Nov 29 18:47:49 CST 2024] No EAB credentials found for ZeroSSL, let's get one
[Fri Nov 29 18:47:51 CST 2024] Registering account: https://acme.zerossl.com/v2/DV90
[Fri Nov 29 18:47:55 CST 2024] Registered
[Fri Nov 29 18:47:55 CST 2024] ACCOUNT_THUMBPRINT='2LgV4qGN_FZP1AftbqQO_JGYld2A6zi-kMixp11ov3I'
base:~# acme.sh --issue -d guzal.cc -d *.guzal.cc --dns --yes-I-know-dns-manual-mode-enough-go-ahead-please
[Fri Nov 29 18:48:15 CST 2024] Using CA: https://acme.zerossl.com/v2/DV90
[Fri Nov 29 18:48:15 CST 2024] Creating domain key
[Fri Nov 29 18:48:15 CST 2024] The domain key is here: /root/.acme.sh/guzal.cc_ecc/guzal.cc.key
[Fri Nov 29 18:48:15 CST 2024] Multi domain='DNS:guzal.cc,DNS:*.guzal.cc'
[Fri Nov 29 18:48:15 CST 2024] Getting domain auth token for each domain
[Fri Nov 29 18:48:25 CST 2024] Getting webroot for domain='guzal.cc'
[Fri Nov 29 18:48:25 CST 2024] Getting webroot for domain='*.guzal.cc'
[Fri Nov 29 18:48:25 CST 2024] Add the following TXT record:
[Fri Nov 29 18:48:25 CST 2024] Domain: '_acme-challenge.guzal.cc'
[Fri Nov 29 18:48:25 CST 2024] TXT value: 'Q35pkQjHEFw_7bgYnucjA7mA89GZohYiesyo1GvUxrM'
[Fri Nov 29 18:48:25 CST 2024] Please be aware that you prepend _acme-challenge. before your domain
[Fri Nov 29 18:48:25 CST 2024] so the resulting subdomain will be: _acme-challenge.guzal.cc
[Fri Nov 29 18:48:25 CST 2024] Add the following TXT record:
[Fri Nov 29 18:48:25 CST 2024] Domain: '_acme-challenge.guzal.cc'
[Fri Nov 29 18:48:25 CST 2024] TXT value: 'bg9jbOU4aSpdWXhIsovbwGaSiIozn0uhuC4JfM9IgxA'
[Fri Nov 29 18:48:25 CST 2024] Please be aware that you prepend _acme-challenge. before your domain
[Fri Nov 29 18:48:25 CST 2024] so the resulting subdomain will be: _acme-challenge.guzal.cc
[Fri Nov 29 18:48:25 CST 2024] Please add the TXT records to the domains, and re-run with --renew.
[Fri Nov 29 18:48:25 CST 2024] Please add '--debug' or '--log' to check more details.
[Fri Nov 29 18:48:25 CST 2024] See: https://github.com/acmesh-official/acme.sh/wiki/How-to-debug-acme.sh
base:~# acme.sh --renew -d guzal.cc -d *.guzal.cc --dns --yes-I-know-dns-manual-mode-enough-go-ahead-please
[Fri Nov 29 18:50:53 CST 2024] The domain 'guzal.cc' seems to have a ECC cert already, lets use ecc cert.
[Fri Nov 29 18:50:53 CST 2024] Renew: 'guzal.cc'
[Fri Nov 29 18:50:53 CST 2024] Renew to Le_API=https://acme.zerossl.com/v2/DV90
[Fri Nov 29 18:50:54 CST 2024] Using CA: https://acme.zerossl.com/v2/DV90
[Fri Nov 29 18:50:54 CST 2024] Multi domain='DNS:guzal.cc,DNS:*.guzal.cc'
[Fri Nov 29 18:50:54 CST 2024] Getting domain auth token for each domain
[Fri Nov 29 18:50:54 CST 2024] Verifying: guzal.cc
[Fri Nov 29 18:51:00 CST 2024] Processing, The CA is processing your order, please just wait. (1/30)
[Fri Nov 29 18:51:05 CST 2024] Success
[Fri Nov 29 18:51:05 CST 2024] Verifying: *.guzal.cc
[Fri Nov 29 18:51:08 CST 2024] Processing, The CA is processing your order, please just wait. (1/30)
[Fri Nov 29 18:51:12 CST 2024] Pending, The CA is processing your order, please just wait. (2/30)
....
[Fri Nov 29 18:53:30 CST 2024] Pending, The CA is processing your order, please just wait. (29/30)
[Fri Nov 29 18:53:44 CST 2024] *.guzal.cc:Timeout
[Fri Nov 29 18:53:44 CST 2024] Please add '--debug' or '--log' to check more details.
[Fri Nov 29 18:53:44 CST 2024] See: https://github.com/acmesh-official/acme.sh/wiki/How-to-debug-acme.sh
[Fri Nov 29 18:53:51 CST 2024] The dns manual mode can not renew automatically, you must issue it again manually. You'd better use the other modes instead.
base:~# acme.sh --renew -d guzal.cc -d *.guzal.cc --dns --yes-I-know-dns-manual-mode-enough-go-ahead-please
[Fri Nov 29 18:53:59 CST 2024] The domain 'guzal.cc' seems to have a ECC cert already, lets use ecc cert.
[Fri Nov 29 18:53:59 CST 2024] Renew: 'guzal.cc'
[Fri Nov 29 18:53:59 CST 2024] Renew to Le_API=https://acme.zerossl.com/v2/DV90
[Fri Nov 29 18:54:01 CST 2024] Using CA: https://acme.zerossl.com/v2/DV90
[Fri Nov 29 18:54:01 CST 2024] Multi domain='DNS:guzal.cc,DNS:*.guzal.cc'
[Fri Nov 29 18:54:01 CST 2024] Getting domain auth token for each domain
[Fri Nov 29 18:54:09 CST 2024] Getting webroot for domain='guzal.cc'
[Fri Nov 29 18:54:09 CST 2024] Getting webroot for domain='*.guzal.cc'
[Fri Nov 29 18:54:09 CST 2024] guzal.cc is already verified, skip dns-01.
[Fri Nov 29 18:54:09 CST 2024] *.guzal.cc is already verified, skip dns-01.
[Fri Nov 29 18:54:09 CST 2024] Verify finished, start to sign.
[Fri Nov 29 18:54:09 CST 2024] Lets finalize the order.
[Fri Nov 29 18:54:09 CST 2024] Le_OrderFinalize='https://acme.zerossl.com/v2/DV90/order/IioDL2UzBaSJ-yuxNQmxfw/finalize'
[Fri Nov 29 18:54:11 CST 2024] Order status is processing, lets sleep and retry.
[Fri Nov 29 18:54:11 CST 2024] Retry after: 15
[Fri Nov 29 18:54:27 CST 2024] Polling order status: https://acme.zerossl.com/v2/DV90/order/IioDL2UzBaSJ-yuxNQmxfw
[Fri Nov 29 18:54:30 CST 2024] Downloading cert.
[Fri Nov 29 18:54:30 CST 2024] Le_LinkCert='https://acme.zerossl.com/v2/DV90/cert/PXeKFpKqP4QpvZgjBWx5pg'
[Fri Nov 29 18:54:31 CST 2024] Cert success.
-----BEGIN CERTIFICATE-----
MIID/TCCA4OgAwIBAgIQctyS748XjdSVtFHG9RL6mDAKBggqhkjOPQQDAzBLMQsw
CQYDVQQGEwJBVDEQMA4GA1UEChMHWmVyb1NTTDEqMCgGA1UEAxMhWmVyb1NTTCBF
Q0MgRG9tYWluIFNlY3VyZSBTaXRlIENBMB4XDTI0MTEyOTAwMDAwMFoXDTI1MDIy
NzIzNTk1OVowEzERMA8GA1UEAxMIZ3V6YWwuY2MwWTATBgcqhkjOPQIBBggqhkjO
PQMBBwNCAARueaei/kebDI+C+dS2L1pH0eX8Qs2w8/bWkd2dSP5HzRuZe32zfggZ
p4gVH9bJILZXBAZKDIPUfrk6vycqlbRPo4ICfzCCAnswHwYDVR0jBBgwFoAUD2vm
S845R672fpAeefAwkZLIX6MwHQYDVR0OBBYEFP5LftXzhyS6Wo1zp7RwQ7bTCu6u
MA4GA1UdDwEB/wQEAwIHgDAMBgNVHRMBAf8EAjAAMB0GA1UdJQQWMBQGCCsGAQUF
BwMBBggrBgEFBQcDAjBJBgNVHSAEQjBAMDQGCysGAQQBsjEBAgJOMCUwIwYIKwYB
BQUHAgEWF2h0dHBzOi8vc2VjdGlnby5jb20vQ1BTMAgGBmeBDAECATCBiAYIKwYB
BQUHAQEEfDB6MEsGCCsGAQUFBzAChj9odHRwOi8vemVyb3NzbC5jcnQuc2VjdGln
by5jb20vWmVyb1NTTEVDQ0RvbWFpblNlY3VyZVNpdGVDQS5jcnQwKwYIKwYBBQUH
MAGGH2h0dHA6Ly96ZXJvc3NsLm9jc3Auc2VjdGlnby5jb20wggEDBgorBgEEAdZ5
AgQCBIH0BIHxAO8AdgDPEVbu1S58r/OHW9lpLpvpGnFnSrAX7KwB0lt3zsw7CAAA
AZN3jpUoAAAEAwBHMEUCIQC5Dp3D8hjucArtPa5BwKyKkpN9zGM40e8IdgIrNlm2
DgIgI/2tLreKvjUX0hMY1ry5zgMpnvkwpq1Xjfu4UBDM0n4AdQDM+w9qhXEJZf6V
m1PO6bJ8IumFXA2XjbapflTA/kwNsAAAAZN3jpU3AAAEAwBGMEQCIBxtQSN/DyGM
szYrq3alOo7q2kdjX0hgPEfeawEdAOBvAiBFwPlznIVyRm5HF22U6zEuNynENfhc
el0SrOLqOSLJtjAfBgNVHREEGDAWgghndXphbC5jY4IKKi5ndXphbC5jYzAKBggq
hkjOPQQDAwNoADBlAjEAwgRhABAtmOqZ8KXibZu/NVr3B1CSXTyAXg4IVPzc0LpK
KSGByqat3/BprAZU1t9sAjAYNTQRcPtNrlBc+Kbd1rQYUNnW/sHcT2SZ8nL3BN7G
yLkkWhF7mzULuBHFrN2dIcs=
-----END CERTIFICATE-----
[Fri Nov 29 18:54:31 CST 2024] Your cert is in: /root/.acme.sh/guzal.cc_ecc/guzal.cc.cer
[Fri Nov 29 18:54:31 CST 2024] Your cert key is in: /root/.acme.sh/guzal.cc_ecc/guzal.cc.key
[Fri Nov 29 18:54:31 CST 2024] The intermediate CA cert is in: /root/.acme.sh/guzal.cc_ecc/ca.cer
[Fri Nov 29 18:54:31 CST 2024] And the full chain certs is there: /root/.acme.sh/guzal.cc_ecc/fullchain.cer

磁盘挂载

磁盘管理工具

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
base:~# modprobe dm-mod
base:~# echo dm-mod >> /etc/modules-load.d/dm.conf
base:~# apk add lvm2
(1/5) Installing libaio (0.3.113-r2)
(2/5) Installing device-mapper-event-libs (2.03.23-r3)
(3/5) Installing lvm2-libs (2.03.23-r3)
(4/5) Installing lvm2 (2.03.23-r3)
(5/5) Installing lvm2-openrc (2.03.23-r3)
Executing busybox-1.36.1-r29.trigger
OK: 489 MiB in 95 packages
base:~# apk add cfdisk
(1/3) Installing libfdisk (2.40.1-r1)
(2/3) Installing libsmartcols (2.40.1-r1)
(3/3) Installing cfdisk (2.40.1-r1)
Executing busybox-1.36.1-r29.trigger
OK: 489 MiB in 98 packages
base:~# apk add xfsprogs
(1/3) Installing inih (58-r0)
(2/3) Installing userspace-rcu (0.14.0-r2)
(3/3) Installing xfsprogs (6.8.0-r0)
Executing busybox-1.36.1-r29.trigger
OK: 490 MiB in 101 packages

对了,别忘记设置自启动 lvm

1
rc-update add lvm boot
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
base:~# cfdisk /dev/sdb

Syncing disks.
base:~# pvcreate /dev/sdb1
Physical volume "/dev/sdb1" successfully created.
base:~# vgcreate vg01 /dev/sdb1
Volume group "vg01" successfully created
base:~# lvcreate -l 100%FREE -n lv01_data vg01
Logical volume "lv01_data" created.
base:~# vgdisplay
--- Volume group ---
VG Name vg01
System ID
Format lvm2
Metadata Areas 1
Metadata Sequence No 2
VG Access read/write
VG Status resizable
MAX LV 0
Cur LV 1
Open LV 0
Max PV 0
Cur PV 1
Act PV 1
VG Size <128.00 GiB
PE Size 4.00 MiB
Total PE 32767
Alloc PE / Size 32767 / <128.00 GiB
Free PE / Size 0 / 0
VG UUID yxNVml-QJiM-OptY-RP3u-3bO0-uYvi-IHK135

格式化逻辑卷

1
2
3
4
5
6
7
8
9
10
11
12
base:~# mkfs.xfs /dev/vg01/lv01_data
meta-data=/dev/vg01/lv01_data isize=512 agcount=4, agsize=16776960 blks
= sectsz=512 attr=2, projid32bit=1
= crc=1 finobt=1, sparse=1, rmapbt=1
= reflink=1 bigtime=1 inobtcount=1 nrext64=1
data = bsize=4096 blocks=67107840, imaxpct=25
= sunit=0 swidth=0 blks
naming =version 2 bsize=4096 ascii-ci=0, ftype=1
log =internal log bsize=4096 blocks=32767, version=2
= sectsz=512 sunit=0 blks, lazy-count=1
realtime =none extsz=4096 blocks=0, rtextents=0
Discarding blocks...Done.

挂载逻辑卷

1
2
3
4
mkdir /data
mount1="/dev/vg01/lv01_data /data xfs defaults 0 0"
echo ${mount1}>>/etc/fstab
mount -a # mount /dev/vg01/lv01_data /data
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
base:~# apk add lsblk
(1/1) Installing lsblk (2.40.1-r1)
Executing busybox-1.36.1-r29.trigger
OK: 491 MiB in 102 packages
base:~# lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
sda 8:0 0 64G 0 disk
├─sda1 8:1 0 300M 0 part /boot
├─sda2 8:2 0 4G 0 part [SWAP]
└─sda3 8:3 0 59.7G 0 part /var/lib/docker
/
sdb 8:16 0 128G 0 disk
└─sdb1 8:17 0 128G 0 part
└─vg01-lv01_data 253:0 0 128G 0 lvm /data
sr0 11:0 1 209M 0 rom

Git Server

我一般选择数据放置于/data目录下;
以下只提供了重要文件,若需要完整的文件也可以在我的 Git 站点Git Server进行下载;

准备

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/data/
├── gitea
│   ├── git
│   ├── gitea
│   └── ssh
├── nginx
│   ├── conf.d
│   │   ├── default.conf
│   │   ├── server
│   │   │   └── gitea.conf
│   │   └── vhost
│   │   ├── guzal.com-443.conf
│   │   ├── guzal.com-80.conf
│   │   └── www.guzal.com-443.conf
│   ├── html
│   │   └── 50x.html
│   └── web_root
│   └── www.guzal.com
└── swarm
├── docker-compose.yml
└── nginx.conf

xx directories, x files

Dockeer-Compose.yml

参考Dockeer-Compose.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
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
[root@primary swarm]# cat docker-compose.yml
version: "3.9"

services:
nginx:
image: nginx:alpine
ports:
- target: 80
published: 80
mode: host
- target: 443
published: 443
mode: host
configs:
- source: nginx
target: /etc/nginx/nginx.conf
secrets:
- source: cakey
target: /etc/nginx/certs/ca.key
mode: 0440
- source: cacer
target: /etc/nginx/certs/ca.cer
mode: 0440
volumes:
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
- /data/nginx/conf.d:/etc/nginx/conf.d
- /data/nginx/html:/usr/share/nginx/html:ro
- /data/nginx/web_root:/usr/share/nginx/web_root:ro
networks:
- inline
depends_on:
- gitea
- registry

gitea:
image: gitea/gitea:1.24.2
environment:
- USER_UID=1000
- USER_GID=1000
- APP_NAME=Where the world builds software
- RUN_MODE=prod
- RUN_USER=git
- DB_TYPE=sqlite3
- DISABLE_SSH=true
- LFS_START_SERVER=true
- REQUIRE_SIGNIN_VIEW=false
- DISABLE_REGISTRATION=true
- DEFAULT_ACTIONS_URL=self
- DOMAIN=git.guzal.cc
volumes:
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
- /data/gitea:/data
networks:
- inline

networks:
host:
external: true
name: "host"
inline:
external: false

configs:
nginx:
file: ./nginx.conf

secrets:
cakey:
file: /root/.acme.sh/guzal.com_ecc/guzal.cc.key
cacer:
file: /root/.acme.sh/guzal.com_ecc/fullchain.cer

注意: 修改本机 ssh 端口,如果需要启用 GitServer 的 ssh 相关功能,建议 Git 使用默认 ssh,所以修改主机 ssh 端口。

启动 Nginx Server (可选)

为 Gitea 提供 HTTPS 能力,也为后续服务的 HTTPS 支持统一提供支持;

nginx.conf

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
user nginx;
worker_processes auto;

error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;

events {
worker_connections 1024;
}

http {
include /etc/nginx/mime.types;
default_type application/octet-stream;

log_format json_analytics '{'
'"msec": "$msec", ' # request unixtime in seconds with a milliseconds resolution
'"connection": "$connection", ' # connection serial number
'"connection_requests": "$connection_requests", ' # number of requests made in connection
'"pid": "$pid", ' # process pid
'"request_id": "$request_id", ' # the unique request id
'"request_length": "$request_length", ' # request length (including headers and body)
'"remote_addr": "$remote_addr", ' # client IP
'"remote_user": "$remote_user", ' # client HTTP username
'"remote_port": "$remote_port", ' # client port
'"time_local": "$time_local", '
'"time_iso8601": "$time_iso8601", ' # local time in the ISO 8601 standard format
'"request": "$request", ' # full path no arguments if the request
'"request_uri": "$request_uri", ' # full path and arguments if the request
'"args": "$args", ' # args
'"status": "$status", ' # response status code
'"body_bytes_sent": "$body_bytes_sent", ' # the number of body bytes exclude headers sent to a client
'"bytes_sent": "$bytes_sent", ' # the number of bytes sent to a client
'"http_referer": "$http_referer", ' # HTTP referer
'"http_user_agent": "$http_user_agent", ' # user agent
'"http_x_forwarded_for": "$http_x_forwarded_for", ' # http_x_forwarded_for
'"http_host": "$http_host", ' # the request Host: header
'"server_name": "$server_name", ' # the name of the vhost serving the request
'"request_time": "$request_time", ' # request processing time in seconds with msec resolution
'"upstream": "$upstream_addr", ' # upstream backend server for proxied requests
'"upstream_status":"$upstream_status"'
'"upstream_connect_time": "$upstream_connect_time", ' # upstream handshake time incl. TLS
'"upstream_header_time": "$upstream_header_time", ' # time spent receiving upstream headers
'"upstream_response_time": "$upstream_response_time", ' # time spend receiving upstream body
'"upstream_response_length": "$upstream_response_length", ' # upstream response length
'"upstream_cache_status": "$upstream_cache_status", ' # cache HIT/MISS where applicable
'"ssl_protocol": "$ssl_protocol", ' # TLS protocol
'"ssl_cipher": "$ssl_cipher", ' # TLS cipher
'"scheme": "$scheme", ' # http or https
'"request_method": "$request_method", ' # request method
'"server_protocol": "$server_protocol", ' # request protocol, like HTTP/1.1 or HTTP/2.0
'"pipe": "$pipe", ' # "p" if request was pipelined, "." otherwise
'"gzip_ratio": "$gzip_ratio", '
'"http_cf_ray": "$http_cf_ray"'
'}';

access_log /var/log/nginx/access.log json_analytics;

sendfile on;
tcp_nopush on;

keepalive_timeout 65;

gzip on;

server_tokens off;

include /etc/nginx/conf.d/*.conf;
include /etc/nginx/conf.d/vhost/*.conf;
include /etc/nginx/conf.d/server/*.conf;
}

default.conf

1
2
3
4
5
6
server {
listen 80 default;
server_name _;

return 405;
}

gitea.conf

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
server {
listen 443 ssl;
server_name git.guzal.com;

http2 on;

ssl_certificate /etc/nginx/certs/ca.cer;
ssl_certificate_key /etc/nginx/certs/ca.key;

client_max_body_size 4096m;

proxy_connect_timeout 3600;
proxy_send_timeout 3600;
proxy_read_timeout 3600;

location ~ .*\.(gif|jpg|png|css|js)(.*) {
proxy_pass http://gitea:3000;
expires 3d;
}

location / {
proxy_pass http://gitea:3000$request_uri;
proxy_set_header X-Real-IP $remote_addr; # pass on real client's IP
}
}

启动 Git Server

1
docker stack deploy --detach=false -c docker-compose.yml base

检查启动情况

1
2
3
CONTAINER ID   IMAGE                COMMAND                  CREATED        STATUS        PORTS                                      NAMES
a3d16a1527f0 nginx:alpine "/docker-entrypoint.…" 15 hours ago Up 15 hours 0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp server_nginx.1.0x3uxtku5ih97t23aj5spybxa
c28db9684db8 gitea/gitea:1.24.2 "/usr/bin/entrypoint…" 17 hours ago Up 17 hours 22/tcp, 3000/tcp server_gitea.1.vxpu78m7sk3l564r6eazjgf27

Gitea Runner (可选)

若需要 Gitea 添加 CI/CD 自动化流程支持,可以参考该章节;

OS:Ubuntu 24.04.2 LTS (Noble Numbat)

  • Gitea Runner

初始化 Runner

To find a listing of our public images on supported Clouds, please use the Cloud Image Locator:
Ubuntu 24.04 LTS (Noble Numbat) Noble Numbat

1
2
3
4
5
6
7
8
9
10
11
12
13
14
root@runner:~# cat /etc/os-release
PRETTY_NAME="Ubuntu 24.04.2 LTS"
NAME="Ubuntu"
VERSION_ID="24.04"
VERSION="24.04.2 LTS (Noble Numbat)"
VERSION_CODENAME=noble
ID=ubuntu
ID_LIKE=debian
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
UBUNTU_CODENAME=noble
LOGO=ubuntu-logo

安装软件包

1
2
3
apt install nano vim tar socat net-tools ethtool wget locate bash-completion tree -y
apt install qemu-guest-agent -y
systemctl enable --now qemu-guest-agent
1
2
3
4
5
6
7
8
9
10
11
apt install ca-certificates curl
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
chmod a+r /etc/apt/keyrings/docker.asc
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://mirrors.aliyun.com/docker-ce/linux/ubuntu $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}") stable" | \
tee /etc/apt/sources.list.d/docker.list > /dev/null
#安装Docker社区版本,容器运行时containerd.io,以及Docker构建和Compose插件
apt update && apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -y
#启动Docker并设置Docker守护进程在系统启动时自动启动
systemctl enable --now docker

安装 act_runner

Gitea 官方 Act Runner 教程

将文件下载或传输至:/usr/bin/act_runner;
还需要编写 systemctl 文件:/etc/systemd/system/act_runner.service;

act_runner.service

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[Unit]
Description=Gitea Actions runner
Documentation=https://gitea.com/gitea/act_runner
After=docker.service

[Service]
ExecStart=/usr/bin/act_runner daemon --config /etc/act_runner/config.yaml
ExecReload=/bin/kill -s HUP $MAINPID
WorkingDirectory=/var/lib/act_runner
TimeoutSec=0
RestartSec=10
Restart=always
User=root

[Install]
WantedBy=multi-user.target

生成 config.yaml

.runner文件所在位置:/var/lib/act_runner

1
2
3
mkdir /etc/act_runner
chmod +x /usr/bin/act_runner
act_runner generate-config > /etc/act_runner/config.yaml # 只需要执行一次,之后,复用现有配置就好

注意:一般这样执行也可:act_runner --config config.yaml register,但是也可以以下方不带交互的命令参考执行即可。 请替换registration_token变量,通过 gitea(uri:admin/actions/runners)获取。

1
2
3
mkdir /var/lib/act_runner
cd /var/lib/act_runner
act_runner --config /etc/act_runner/config.yaml register --no-interactive --instance https://git.guzal.cc --token <registration_token> --name primary --labels "LocalRunner:host"

actions workflow

下载 Github Actions 里的所有 actions

参考:

1
2
3
4
git clone --bare https://github.com/actions/checkout

git push --all https://git.guzal.cc/actions/checkout.git
git push --tags https://git.guzal.cc/actions/checkout.git

Gitea 配置 Act Runner

可以根据需求管理员身份设置默认 Act Runner;