乱码三千 – 分享实用IT技术

乱码三千 – 码出一个新世界


  • 首页

  • 归档

  • 搜索

supervisor和systemd的对比

发表于 2022-09-21

前言

过去我们项目组的应用都是用 supervisord 托管的。最近因为某些因素,无法使用 supervisord,因此考虑改用 systemd。

systemd作为主流 Linux 发行版的默认选项,之前多多少少用过一点 systemd。不过这次需要上生产环境,所以抽空深入研究一番。

为什么要用supervisord?

  1. 实现进程的分组管理,比如支持一同启动/停止多个生产者/消费者实例。
  2. 进程崩溃的时候可以重启

要想改用 systemd,需要看下systemd 如何应对这两个问题。
(如无指明,在本文中,supervisord 的配置项在 [program:x] 下面,而 systemd 的配置项则位于 [Service])

进程控制

无论 supervisord 还是 systemd,都采用 ini作为配置文件的格式。跟 supervisord 不同的是,systemd 每个程序都要单独开一个unit文件。

supervisord 可以同时启动/停止配置文件中所有的进程(或者某个进程组配置中的进程)。systemd可以用依赖来实现这一点。下面例子中,我们
就创建了一个可以同时管理的进程组:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
; group.target
[Unit]
Description=Application
Wants=prog1.service prog2.service
; prog1.service
[Unit]
Description=prog1
PartOf=group.target

[Service]
ExecStart=/usr/bin/prog1
Restart=on-failure
; prog2.service
[Unit]
Description=prog2
PartOf=group.target

[Service]
ExecStart=/usr/bin/prog2
Restart=on-failure

systemctl start group.target,prog1 和 prog2 也会带起来。systemctl restart group.target,prog1 和 prog2 也会跟着重启。

相对来说,supervisord 的做法更加直观一些。

如果要更改supervisord的配置文件,supervisord 需要运行 supervisorctl reread 才会生效。
而 systemd 则需要 systemctl daemon-reload。半斤八两吧。

不过 supervisord 有一个好。如果你不知道哪些程序的配置改变了,简单地执行 supervisorctl update,所有涉及的进程都会被重启。
而 systemd 貌似做不到这一点。

systemd 可以指定 stop 操作时可以选择的命令(ExecStop=)。另外它还提供了 ExecReload=,可以自定义调用 systemctl reload xxx 重新读取程序配置文件时的操作。
supervisord不支持 reload 指定进程。同时对于 stop操作,它只允许你选择要发送哪种信号…

supervisord 的 stopwaitsecs 可以控制stop 操作后等待程序退出的耐心(以秒衡量)。待给定的耐心都消耗完毕后,supervisord 才会痛下杀手,发送 SIGKILL。

systemd 对应的配置项是 TimeoutStopSec=。systemd 会给多一次机会,在下最后通牒之前,会先发送 SIGTERM,过另一个TimeoutStopSec之后才发送 SIGKILL。

进程重启

为了避免在supervisord 和 systemd两套术语间迷糊,请允许我抛弃所有术语,用自己的话描述。
life-cycle

从上图可以看到,进程在 RUNNING 之前,会有一个 STARTING 的过程。在 STARTING 过程中,进程可能会读取配置文件,进行初始化。
这一过程中的错误处理,跟 RUNNING 状态的应当有所不同。
以上是supervisord的想法。

所以supervisord 提供了单独的 startretries 配置项,用来配置 STARTING 阶段的重启次数。
systemd 对此没有特殊处理。

一个程序,从 RUNNING 到 EXITED,有两种可能:正常退出或异常退出…(废话)
这两种情况,是通过配置的退出码来区分的。对于 supervisord,这个配置项是 exitcodes。systemd 则通过 SuccessExitStatus 来控制。
有趣的是,exitcodes 的默认值是 0,2,不知道为何它会认为 2 也是正常的退出码。

如果配置了 autorestart = true,只要程序退出,supervisord 都会把它启动起来。相对的,如果配置的是 autorestart = unexpected,则只有
异常退出才会重启。这两个选项,在 systemd 里对应 Restart=always 和 Restart=on-failure。systemd 还提供了 Restart=on-success(只有正常
退出才重启)和 Restart=on-abort(只有收到异常信号才重启)。

对于重启次数,supervisord 没有作限定。因为重启一个程序时,supervisord 会先让它处于 STARTING 状态。这个状态的持续时间,是由配置项
中的 startsecs 决定的,默认 1 秒。如果是不可恢复的错误,程序就不可能成功进入到 RUNNING 状态。当然也许存在这样的情况,程序运行 1 秒
后,就会崩溃。那么它就会陷于不停重启的无间地狱。

systemd 对此一如既往,提供了 N 多选项以供采用。你可以用 RestartSec 控制每次重启的间隔,可以用 StartLimitInterval 和 StartLimitBurst 设定
给定周期内能够重启的次数。比如指定 StartLimitInterval=1s,StartLimitBurst=3,就可以实现跟 supervisord 一致的默认重启策略。

比较完最基本的两种功能,让我们继续看看,两者在一些小细节上的对对碰。

控制实例数

supervisord 可以用 numprocs 来控制单个程序对应的实例数。systemd 也可以做到这一点,虽然有点麻烦(某种意义上,更加强大)。
systemd 会把以 @ 结尾的 service 文件当作模板,在运行时根据给定的参数展开成多个实例。

具体实现方式见:http://0pointer.de/blog/proje…

日志

supervisord 能够重定向被托管的程序的 stdout 和 stderr 到日志文件中,并提供日志切割服务。systemd 也支持这一点,尽管它的实现有很大的不同。

根据鄙人的经验,基于定期检查的日志切割服务,不是个好的选择。
一旦遇上突发高峰,有可能会出现日志无法及时切割的情况;而调小检查间隔,大部分情况下都在无意义地空转。(说的就是你,logroated)
好在无论是 supervisord,还是systemd,提供的切割服务都是实时的。每当写入内容会超过上限时,就会自动切割。

systemd 的日志服务是通过 journald 组件实现的。你可以在 /etc/systemd/journald.conf 中配置它。
journald 默认的日志存储形式是 Storage=auto。这个选项比较奇妙,如果你创建了 /var/log/journal 文件夹,那么它就会把日志写到这个文件夹下。否则不进行持久化。

持久化后的日志是这个样子的:

1
2
3
4
/var/log/journal/c4010ceea79847afbedecb60a775db96/
├── system.journal
├── user-1000.journal
└── user-65534.journal

第一次看到这样的目录结构,说不定你会大吃一惊。journald 设计者脑洞不是一般的大。从这个结构上,根本看不出应用日志在哪里嘛。
不,完全没有这样的必要,因为所有的程序的日志都会写到一块去。不分彼此,全变成一团浆糊。随便一提,日志默认都是压缩的。

要看日志,你得用 journalctl。比如看 prog1.service 的日志,需要 journalctl -u prog1.service。要看特定时期的日志,需要 journalctl --since $timestamp --until $timestamp。

这么前卫的设计我可接受无能。这种 journalctl 控制一切的方式,导致 systemd 日志无法集成到传统的日志收集工具中。
程序员工具箱中各种 text base 处理工具,对此也大眼瞪小眼,只能对着 journalctl 低三下四,接受对方的小脾气。

journald 提供了三个配置项,RuntimeMaxFileSize= 和 RuntimeMaxFiles=。顾名思义,就是单个日志文件大小和允许的日志数。
另外,RuntimeMaxUse= 和 RuntimeKeepFree= 可以控制总大小的上限。

supervisord 在这方面做的要好得多。通过 stdout/stderr_logfile_maxbytes 和 stdout/stderr_logfile_backups,你可以规划每一个程序的日志文件的切割粒度。
不同程序的日志不会挤一起,产生日志少的程序也不会被产生日志多的程序干扰。

开机自启

systemd 支持开机自启, 而supervisor开机自启需依赖其他程序实现, 其本身也是被监控的对象

systemd vs supervisord

除了以上几点外,还有一些没有具体提到的功能。
比如 supervisord 通过 priority 配置进程启动顺序,以及 systemd 对应的 Before/After 依赖机制。
比如 supervisord 的 events 功能,和与之相对应的 systemd 的 notify 机制。
比如 supervisord 可以管理 fastcgi(真有人这么做吗)。
比如 systemd 提供的基于 cgroup 的资源限制。
由于没有使用经验,对这些功能就不作一一比较了。

总结

systemd和 supervisord 各有长短,不存在哪一方绝对的碾压。

systemd 跟Linux 紧密结合,所需的依赖少,其提供的保障自然比 supervisord 更可靠。然而在强大的能力背后,也有配置复杂、不易上手等问题。

supervisord偏于应用层,却因此有独特的用武之地。

举个例子,许多人会往 docker打包里面封入一份supervisord,让它来做 PID 1,以此稍微增强下健壮性。
换 systemd 做同样的事,就像用园艺剪刀裁纸,即使能够顺利完成,也难免事倍功半。毕竟这样的方式跟systemd 的设计是背道而驰的。

本文转载自: segmentfault

乱码三千 – 点滴积累 ,欢迎来到乱码三千技术博客站

如何使用supervisor实现内网穿透持久化

发表于 2022-09-21

前言

使用内网穿透时 可能会出现各种不稳定因素导致服务中断, 一旦中断 那么外网就无法对内网进行访问了

为了保证连接的持久稳定性, 我们需要对进程进行监控, 一旦发现服务掉线或者出错 就自动重启程序

为了实现这个需求, 我们可以用supervisor, 它是由python写的一个进程管理工具, 主要功能有:

  • 启动、重启、关闭进程
  • 服务挂掉后,自动重启
  • 可执行文件或者配置文件修改后,服务自动重启
  • 内置可视化界面管理

上一章给大家介绍了《使用frp进行内网穿透实现外网访问局域网中的服务器》

由于服务端使用的是第三方的中转服务器, 服务器的稳定性暂不考虑, 目前只需关心客户端这一块, 这里 我以内网中Mac机器为例给大家介绍supervisor的使用

开始实现

  1. 安装supervisor

    1
    brew install supervisor

    或者

    1
    sudo pip3 install supervisor
  2. 检查是否安装成功

    1
    brew info supervisor

    或者

    1
    brew info supervisor

    显示版本号则说明安装成功

  3. 创建配置文件

    在/usr/local/etc/目录下创建一个配置文件名为supervisord.conf

    1
    touch supervisord.conf
  4. 配置服务

    在配置文件中添加以下内容

    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
    [inet_http_server]         ;开启http服务 
    port=127.0.0.1:9001 ;指定端口号为9001
    username=user ; 用户名
    password=123 ; 密码



    [supervisord]
    logfile=/tmp/supervisord.log ; 日志文件
    logfile_maxbytes=50MB ; 日志文件最大50Mb
    logfile_backups=10 ; 日志备份数量
    loglevel=info ; 打印日志的等级 默认为info 除此之外还有 debug,warn,trace
    pidfile=/tmp/supervisord.pid ;pid文件路径
    nodaemon=false ; 是否在前台运行
    silent=false ;是否关闭日志打印
    minfds=1024
    minprocs=200


    [supervisorctl]
    serverurl=http://127.0.0.1:9001 ;访问这个服务进行进程管理
    username=user ; 需要和http用户名保持一致
    password=123 ; 需要和http密码保持一致 用于管理工具的连接 如果不配置的话 每次使用supervisorctl都得手动输入用户名密码


    [rpcinterface:supervisor] ;这个配置必须要有
    supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface

    配置详解:

    • [inet_http_server]: 开启http服务 提供可视化监控界面
    • [supervisord]:supervisor服务配置 缺少它supervisor无法启动
    • [supervisorctl]:supervisor管理工具
  1. 启动supervisor

    1
    supervisord -c /usr/local/etc/supervisord.conf

    启动后 我们在浏览器中输入http://127.0.0.1:9001, 填入配置文件中的username和password, 进入到守护进程管理页面

    image-20220921152026301

    我们在页面中为发现进程信息, 因为还没有配置需要进行守护的进程

  2. 添加需要进行监测并守护的进程

    在配置文件中追加以下内容:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    [program:frpc] ;名称为frpc  这个可以自定义 但是不能重复
    command=/Users/songjian/frp/frpc/frpc -c ./frpc.ini ; 需要运行的程序指令
    directory=/Users/songjian/frp/frpc ;程序目录
    autostart=true ; supervisor 启动时跟随启动
    autorestart=true ; 程序崩溃时自动重启
    startsecs=5 ; # of secs prog must stay up to be running (def. 1)
    startretries=3 ;重试次数
    stdout_logfile=/Users/songjian/frp/frpc/supervisord.log ; 日志文件路径
    stdout_logfile_maxbytes=20MB ; 日志文件最大容量
    stdout_logfile_backups=10 ; # 日志备份数量
  3. 重载配置文件

    1
    supervisorctl

    执行后提示需要验证 输入用户名和密码后进入子命令窗口, 然后输入reload进行重载:

    image-20220921172100244

    此时我们刷新浏览器可以看到守护的程序已经启动:

    image-20220921173043546

    我们可以直接在浏览其中直接对其进行重启 停止 以及日志查看等操作

    至此 我们supervisor对frpc的守护已初步实现

supervisor开机自启

我们希望内网机器开机后自动启动supervisor, 在Mac平台实现很简单, 只需执行以下指令即可:

1
brew services start supervisor

brew services内部使用的是launchctl, 简化了launchctl的繁琐操作, brew services的常用命令有:

1
2
3
4
5
6
brew services list  # 查看使用brew安装的服务列表
brew services run formula|--all # 启动服务(仅启动不注册)
brew services start formula|--all # 启动服务,并注册
brew services stop formula|--all # 停止服务,并取消注册
brew services restart formula|--all # 重启服务,并注册
brew services cleanup # 清除已卸载应用的无用的配置

supervisorctl管理工具提供的功能

我们可以利用supervisorctl对我们的守护进行进行启动 停止 重启等操作, 具体的可以输入help进行查看:

image-20220921172300446

  1. 停止 supervisor

    1
    shutdown

    该指令不仅会停止 supervisor, 还会停止其守护的所有程序

  2. 停止某个守护进程

    1
    stop 进程名
  3. 停止所有守护进程

    1
    stop all
  4. 重启某个守护进程

    1
    restart 进程名
  5. 重载整个配置文件

    1
    reload

    所有子进程会重启

  6. 更新配置文件

    1
    update

    配置文件中有改动的进程会被重启 没有改动的不受影响

本文为作者原创转载时请注明出处 谢谢

乱码三千 – 点滴积累 ,欢迎来到乱码三千技术博客站

使用frp进行内网穿透实现外网访问局域网中的服务器

发表于 2022-09-20

前言

之前给大家介绍过使用内网云实现内网穿透的方案, 一行指令搞定, 详见《使用内网云进行内网穿透实现外网访问局域网中的服务器》

今天给大家介绍如何使用frp实现内网穿透

frp是一个免费开源的内网穿透工具, 包含服务端(frps)和客户端( frpc)

Github

假如你自己有云服务器, 那么将服务端安装到具有公网ip的服务器中, 将客户端安装到内网的机器上, 即可实现内网穿透功能

当然 如果你没有云服务也没有关系 网上有些热心肠的大佬们给我们提供了中转服务器 比如: freefrp:

image-20220920172928529

而我们要做的仅仅就是在内网的机器上安装用于连接的客户端即可

接下来我以本地的Mac电脑为例 充当内网机器 介绍使用方法

使用方法

http穿透

  1. 首先下载客户端程序

    点击下载

    image-20220920173201984

    由于是Mac系统 因此我们选择Darwin_amd64, 下载后解压:

    image-20220920174602538

    客户端只用frpc开头的文件, 其他的可以移除,

  2. 修改配置文件

    打开配置文件frpc.ini, 然后修改成以下内容:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    [common]
    server_addr = frp.freefrp.net
    server_port = 7000
    token = freefrp.net

    [mac_http]
    type = http
    local_ip = 127.0.0.1
    local_port = 13000
    custom_domains = git.newban.cn

    image-20220921101048772

    参数详解:

    • 中括号中的名称可以自定义 但不能重复

    • type: 表示连接类型, 支持http/https udp tcp 等协议

    • server_addr:服务器 IP 地址或者域名地址

    • *server_port *:服务端口号

    • token:服务端访问密码

    • local_ip: 需要进行穿透的内网ip, 通常为127.0.0.1 如果使用虚拟机或者docker 建议改成局域网ip

    • local_port: 需要进行穿透的内网端口号

    • custom_domains: 自定义域名 需要将域名解析到服务器地址 这样使用域名就能直接访问到内网程序了

  1. 域名解析

    将配置文件中的自定义域名以CNAME的方式解析到frp.freefrp.net

  2. 启动frpc客户端程序

    1
    ./frpc
  3. 浏览器访问

    此时 我们通过域名就能直接在任意浏览器上访问到127.0.0.1:3000

  4. 多域名解析

    假如我们需要将多个不同域名同时解析到同一个内网程序, 那么只需增加一个新模块, 配置如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    [common]
    server_addr = frp.freefrp.net
    server_port = 7000
    token = freefrp.net

    [mac_http]
    type = http
    local_ip = 127.0.0.1
    local_port = 13000
    custom_domains = git.newban.cn


    [mac_http2]
    type = http
    local_ip = 127.0.0.1
    local_port = 13000
    custom_domains = git.insoan.com
  1. 实现以Web的形式可视化配置客户端

    只需在common的节点下配置admin参数即可, 如下:

    1
    2
    3
    4
    5
    6
    7
    8
    [common]
    server_addr = frp.freefrp.net
    server_port = 7000
    token = freefrp.net
    admin_addr = 127.0.0.1 #客户端Web管理地址
    admin_port = 7122 #客户端Web管理端口
    admin_user = admin #客户端Web管理用户名
    admin_pwd = 123456 #客户端Web管理密码

    配置完后重启frp, 然后在浏览器输入http://127.0.0.1:7122, 即可以Web的形式监控当前正在穿透的程序:

    image-20220922115156138

ssh穿透

  1. 配置TCP连接

    如果我们需要进行ssh访问, 那么我们需要在客户端配置tcp协议, 配置如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    [common]
    server_addr = frp.freefrp.net
    server_port = 7000
    token = freefrp.net

    [mac_http]
    type = http
    local_ip = 127.0.0.1
    local_port = 13000
    custom_domains = git.newban.cn

    [mac_ssh]
    type = tcp
    local_ip = 127.0.0.1
    local_port = 22
    remote_port = 12323

    参数解析:

    • remote_port: 服务器端口映射 意思就是将服务器的12323端口映射到内网的22端口
  2. ssh访问

    此时 我们在命令窗口执行以下指令就可以进行ssh连接了

    1
    ssh -p 12323 root@frp.freefrp.net

    由于我们之前将自定义域名以CNAME形式解析到了frp.freefrp.net, 所以 我们也可以用自定义域名进行连接, 如下:

    1
    ssh -p 12323 root@git.newban.cn

总结

至此 我们的内网穿透客户端配置就ok了, 相比内网云 使用frpc+freefrp.net中转服务器的模式进行内网穿透可以实现完全免费且稳定的服务

下一章 给大家介绍《如何使用supervisor实现内网穿透持久化》

本文为作者原创转载时请注明出处 谢谢

乱码三千 – 点滴积累 ,欢迎来到乱码三千技术博客站

使用内网云进行内网穿透实现外网访问局域网中的服务器

发表于 2022-09-20

前言

有时候我可能会借助家里的电脑临时充当服务器供外网访问, 此时需要进行内网穿透才能实现

网上偶然发现一个提供内网穿透服务的网站, 名为内网云:

image-20220920162143938

如果是临时使用 那么完全免费, 付费的话5块钱一个月

接下来给大家介绍 如何使用

使用指南

http映射

假设我的电脑上开了一个Web服务, 地址为:http://localhost:3000, 我们想实现外网访问到这个地址的内容, 此时我们可以在电脑的命令窗口中输入以下指令:

1
ssh -R 80:127.0.0.1:3000 sh@sh3.neiwangyun.net

指令解析:

  • ssh:ssh远程命令
  • -R:远程端口绑定
  • 80:固定端口
  • 127.0.0.1:固定的本机网络
  • 3000:你需要转发的网络端口,自行更改
  • sh:默认匿名账号,不需要密码验证
  • sh3.neiwangyun.net:内网云服务器节点的地址,固定值

简而言之 这句指令的意思就是将sh3.neiwangyun.net服务器的80端口转发到本地的3000

执行完毕后出现以下内容:

image-20220920162759901

结果解析:

  • username:sh账号名称
  • type:anonymous账号类型
  • subdomain: xxxxxxxxxx.neiwangyun.net 子域名
  • bandwidth: random 网络带宽
  • expire_time: random过期时间
  • unid: 唯一识别码
  • http:http链接
  • https:https链接
  • ipport:直连用的ip和端口
  • remote_ip:客户端ip,服务器看到的连接者IP

此时 我们在浏览器中输入http/https的地址则可以访问到http://localhost:3000的内容

ssh映射

假如我们需要在外网中对家里的电脑进行ssh连接, 那么我们需要更改指令端口,如下:

1
ssh -R 80:127.0.0.1:22 sh@sh3.neiwangyun.net

image-20220920164300687

执行完毕后 我们需要用ipport的值进行ssh访问, 如下:

1
ssh hostname@olveddnzffdhshsh3.neiwangyun.net:31258

本文为作者原创转载时请注明出处 谢谢

乱码三千 – 点滴积累 ,欢迎来到乱码三千技术博客站

本地nginx反向代理localhost端口转发失败的解决方案

发表于 2022-09-20

问题

有时候为了方便 懒得开虚拟机直接将nginx部署在了本地, 在进行端口映射测试时可能会出现访问502 Bad Getway的问题

我们先来分析一下nginx的配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
http{

upstream gitea{
server 127.0.0.1:13000;
}
server{
listen 80;
server_name localhost;
location / {
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://gitea;
break;
}
}

}

这里我们将127.0.0.1:13000映射给了localhost:80, 如果我们在浏览器中输入localhost显然是无法访问的

解决方案

如果想要正常访问 需要将127.0.0.1改成局域网ip地址, 修改后的配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
http{

upstream gitea{
server 192.168.13.155:13000;
}
server{
listen 80;
server_name localhost;
location / {
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://gitea;
break;
}
}

}

重启nginx使配置生效, 此时即可正常转发访问了

本文为作者原创转载时请注明出处 谢谢

乱码三千 – 点滴积累 ,欢迎来到乱码三千技术博客站

关于使用ssh进行仓库clone端口号非22的解决办法

发表于 2022-09-19

问题

我们在使用docker搭建私有git仓库时, 会将容器的22端口映射到宿主的其他端口上, 此时如果我们使用ssh地址进行仓库clone, 则会报错 提示ssh: connect to host localhost port 22: Connection refused:

image-20220920121534132

假设映射到宿主的端口号为10022, 那么解决方案如下:

解决方案

  1. 第一种 clone时指定端口号:

    1
    git clone ssh://git@localhost:10022/songjian/ggg.git

    注意: 需要带上ssh://这个协议头

  2. 第二种 在.ssh目录下的config文件中增加port字段指定端口访问:

    1
    2
    3
    4
    5
    Host localhost
    HostName localhost
    Port 10022
    PreferredAuthentications publickey
    IdentityFile ~/.ssh/id_rsa

    由于git默认port是22, 此时我们修改后则可以按照正常的形式进行仓库的克隆:

    1
    git clone git@localhost/songjian/ggg.git
  3. 第三种 使用nginx反向代理

    在nginx.conf文件中配置如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    stream {
    upstream ssh-proxy {
    server 服务器ip:10022;
    }
    server {
    listen 22;
    proxy_pass ssh-proxy;
    }
    }

    配置好后, 直接正常形式clone:

    1
    git clone git@localhost/songjian/ggg.git

本文为作者原创转载时请注明出处 谢谢

乱码三千 – 点滴积累 ,欢迎来到乱码三千技术博客站

使用Docker搭建基于gitea的私有git仓库

发表于 2022-09-19

前言

最近打算将一些私有仓库转移到自己服务器上, 以备不时之需, 目前免费开源的Git仓库框架有Gitlab和Gitea, 考虑到资源消耗问题, 果断选择了Gitea

Gitea的Github地址

接下来分享我个人使用Docker快速搭建Gitea的过程

步骤如下

安装gitea

  1. 搜索gitea镜像

    1
    docker search gitea
  2. 拉取gitea镜像

    1
    docker pull gitea/gitea
  3. 创建并运行容器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    docker run -id \
    --privileged=true \
    --restart=always \
    --name=c_gitea \
    -p 10022:22 \
    -p 13000:3000 \
    -v /root/app/gitea:/data \
    -h c_gitea \
    gitea/gitea:latest

    参数详解:

    • privileged: 是否授予容器root权限
    • restart : docker启动是是否自动启动容器
    • name: 表示容器别名
    • -p 10022:22: 容器暴露了22和3000端口
    • -v /root/app/gitea:/data: 容器的data目录挂载到/root/app/gitea
  4. 浏览器访问gitea配置页面

    1
    http://服务器ip:13000

    image-20220919172350179

    这里主要需要配置数据库以及域名 其他的保持默认即可

    首先数据库的话 这里有多种数据库可选, 考虑到资源消耗和移植方便 我选择sqlite3

    那么在进行配置之前 我们需要先安装sqlite3来创建数据库文件

    依然使用docker快速安装:

安装sqlite3

  1. 拉取镜像

    1
    docker pull nouchka/sqlite3
  2. 创建并运行容器

    1
    2
    3
    4
    5
    6
    7
    docker run -id \
    --restart=always \
    --name=c_sqlite \
    -p 1433:1433 \
    -v /root/app/gitea/sqlite:/root/db \
    -h c_sqlite \
    nouchka/sqlite3:latest
  3. 进入容器

    1
    docker exec -it c_sqlite bash
  1. 进入容器后运行指令创建数据库

    1
    sqlite3 数据库名.db

    运行创建数据库指令时 sqlite3默认会在当前目录生成db文件, 所以执行前要确保当前目录为挂载目录,也就是/root/db

    image-20220919182016029

    执行`sqlite3`进入`SQL`状态, 此时我们输入`.database`可以查看并刷新已经创建的数据库文件 这一步关键 否则宿主挂载目录文件不更新
  2. 退出数据库

    1
    .quit

    image-20220919182305343

    此时我们在宿主的`/root/app/gitea/sqlite`可以查看到刚刚生成的数据库

数据库关联

我们需要明白的是, 在docker中gitea容器是个独立的系统, 在配置页面中填写的路径皆为gitea容器内部路径, 而非宿主路径

由于gitea容器的/data目录映射到了宿主的/root/app/gitea目录, 因此 我们需要将生成的sqlite数据库文件放置在宿主的/root/app/gitea目录下, 这样gitea容器才能访问到数据库文件

这一点 我在sqlite容器创建时已经考虑到了, 所以将sqlite挂载目录设为了/root/app/gitea/sqlite, 从而免去了数据库文件的迁移

此时 我只需在配置页面数据库路径一项填入/data/sqlite/gitea.db即可:

image-20220920101539648

如果后期需要修改配置可以进入/root/app/gitea/gitea/conf/app.ini 进行修改, 每次修改后记得需要重启gitea容器才能生效

配置完毕后 点击安装

紧接着自动跳转到登录页面, 此时我们注册一个新账号然后登录:

image-20220920102423120

至此 我们的私有仓库就搭建完毕了, 如果需要节省资源, 可以将sqlite容器停止, 它的存在只是为了创建数据库 以及必要的时候进行数据自定义处理, 暂时不需要它保持运行状态

外部仓库同步

gitea支持从外部仓库导入 支持以下常见厂商:

image-20220920103201263

如果从github 导入 首先需要去github中申请一个access token

image-20220920104007824

当然我们也可以直接使用clone的形式进行迁移 无需token:

image-20220920115211964

后面的就不多介绍了

自定义域名

正常情况下我们可以通过地址http://服务器公网IP:13000来访问服务器, 如果需要配置自定义域名, 那么需要修改一些配置:

首先域名端, 也就是域名解析需要指向服务器IP, 这点不做过多介绍 大家都明白

另外就是服务端

由于我使用了Nginx进行反向代理, 并且给docker配置了桥接网络, 所以在nginx.conf文件中配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
http{
upstream gitea{
server c_gitea:3000;
}
server{
listen 80;
server_name git.newban.cn;
location / {
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://gitea;
break;
}
}

}

通过桥接网络 我们可以直接使用容器别名实现容器间的相互通信, 减少端口暴露的风险

gitea目录结构

数据库主要用于存放用户和仓库相关的配置数据

image-20220920112051764

而我们的代码主要是放在了本地磁盘的/root/app/gitea/git目录下:

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
.
├── git
│   ├── lfs
│   └── repositories
├── gitea
│   ├── attachments
│   ├── avatars
│   ├── conf
│   ├── home
│   ├── indexers
│   ├── jwt
│   ├── log
│   ├── packages
│   ├── queues
│   ├── repo-archive
│   ├── repo-avatars
│   ├── sessions
│   └── tmp
├── sqlite
│   └── gitea.db
└── ssh
├── ssh_host_dsa_key
├── ssh_host_dsa_key.pub
├── ssh_host_ecdsa_key
├── ssh_host_ecdsa_key.pub
├── ssh_host_ed25519_key
├── ssh_host_ed25519_key.pub
├── ssh_host_rsa_key
└── ssh_host_rsa_key.pub

本文为作者原创转载时请注明出处 谢谢

乱码三千 – 点滴积累 ,欢迎来到乱码三千技术博客站

Android Studio关于插件市场Marketplace无法搜索的问题解决

发表于 2022-09-17

问题

有的小伙伴在进行插件搜索时可能会出现搜索空白的情况, 界面显示Not Found

此时 只需要设置一下国内代理即可:

image-20220916162230660

进入代理设置, 勾选自动代理 并输入以下地址:

1
http://mirrors.neusoft.edu.cn:80

重新搜索 OK

本文为作者原创转载时请注明出处 谢谢

乱码三千 – 点滴积累 ,欢迎来到乱码三千技术博客站

自建 Git 服务器:Gitea 与 Gitlab 部署踩坑经历与对比总结

发表于 2022-09-17

前言

这一周我都在折腾在自己的内网服务器中部署私有 Git 服务器,对于目前用的最广泛的 Gitea 与 GitLab 都进行了实际部署,并邀请了多人进行试用。

对于这两个被广泛使用的可自托管的 Git 托管方案,网上似乎都是几张清单式的功能对比表,所以我想在这篇文章中对比两者在我实践中感受到的的差别,以及说说这几天我趟过的坑,为准备自建 Git 托管网站的用户提供参考与建议。

在正文开始前,我先提醒一件事情:不推荐在非自己托管的 Gitea 上使用 GitHub TOKEN 等个人敏感信息,目前(v1.16.4) Gitea 的隐私管理缺陷可能会向站点管理员泄露你的隐私。这个问题可以说是我遇到的最大的坑,也是让我转向 GitLab 的主因,我会在正文中详细说明这个问题。

更新:Gitea v1.16.6 已经修复了泄露 TOKEN 的问题,但对于切记注意第三方 Gitea 托管站点的版本。

在本文发布后,Gitea 作者已经看到了部分对 Gitea 缺失功能的吐槽,并开始在新版本中实现它们,所以部分内容可能有所过时。

概述

作为可以自己部署的 Git 托管服务器方案,Gitea 与 GitLab 有很多相似之处:有着和 GitHub 相似的仓库界面,一样有着基本的 Git Server 功能,一样同时支持 http(s) 与 ssh,一样支持 Issue 和 Pull requests……

Gitea 是完全开源免费的项目,而 GitLab 有着开源并免费的版本 GitLab CE,也有付费并有闭源功能的 GitLab EE。它们也都提供了由各自的官方托管版网站,你可以前往 gitea.com 与 gitlab.com 体验它们的用法。

这些最基础的东西双方都很相似,只看双方提供的功能对比表很难感受出它们有多大差别,但在实际部署它们后,你可以很直观地感受到它们骨子里就是不同的,它们之间的区别就和 com.sun.net.httpserver 和 Spring 全家桶一样,是单一功能的库与一个生态的区别。

Gitea 是一个功能较为单一的 Git 托管服务器,所有功能都围绕着 Git 托管而来,而且给出了较高的可定制性。在部署 Gitea 的时候,我很明确自己的目的是实现 Git 托管功能,部署后我再根据自己的需求去组合其他工具来满足我的工作流。

GitLab 则是一个大而全的解决方案整合,将 Git 托管、持续集成/部署等功能做在了一起,试图解决你的所有需求。在我部署它之后,我需要探索它的功能,学习它的工作流,适应它来完成我的工作。

资源占用

作为 Git 托管服务器使用时,Gitea 资源占用明显要低得多。

静态硬盘占用上,Gitea 核心是一个 100 MiB 上下的可执行文件,外加上作为必要依赖的 Git(如果内置 SQLite 不够的话也需要单独部署一个 MySQL 或者 PostgreSQL 做数据库),而 GitLab 光 Docker image 大小就 GiB 级了……不用我多说,截一下 GitLab 的日志文件夹就知道这玩意有多重量级了:

1
2
3
4
$ ls ./gitlab/logs
alertmanager gitlab-kas gitlab-workhorse nginx prometheus redis sshd
gitaly gitlab-rails grafana postgres-exporter puma redis-exporter
gitlab-exporter gitlab-shell logrotate postgresql reconfigure sidekiq

我断断续续跑了两天,这日志就快 200MiB 了……

内存方面,我这里 Gitea 日常占用内存通常在几百 MiB 浮动,而 GitLab 的 Docker 容器目前内存占用是 14GiB。

GitLab CPU 占用率(相对于一个核心计算)日常待机在 35% 上下,而 Gitea 通常是 0.2% 左右。(这些都是日常无负载状态下的情况,如果有机会的话我试试进一步比较,现在正在停用 GItea,懒得折腾了。)

网站配置

Gitea 大部分配置都要通过修改 app.ini 并重启 Gitea 服务器来应用,后台管理面板基本没有可修改的配置,不能进行配置热修改。

GitLab 部分网络相关的配置(域名,端口,代理,邮箱等)需要修改 gitlab.rb 并重启 GitLab,剩下的大多选项都是在管理员面板里通过 Web UI 进行热修改并及时生效。

对于要稳定运行的 Git 托管服务器来说,Gitea 每次修改配置后想要生效都要离线一段时间,好在 Gitea 启动很快,我这里从启动到能正常访问大概只要 10 秒钟(数据库跑在另一个容器里,没有计算它的启动时间),而 GitLab 启动一次要一分多钟,但由于 GitLab 大部分配置都是热修改,除了最开始部署时需要修改配置,运行中基本没有重启的需求。

想要自定义页面布局在 GitLab 上非常困难,除了首页内容可以通过管理面板修改外,剩下的地方似乎都无法用常规手段修改。Gitea 放开了很多 tmpl 文件可配置,我想要给站点每个页面底部添加一条链接,自己提供一个 extra_links_footer.tmpl 就能完成,但在 GitLab 我是没有找到什么好办法去实现。(似乎能改 /var/opt/gitlab 里的东西来修改布局,但我改了这个文件夹里的一些配置后再重启后,我修改的地方都被还原了,有空再做进一步的探索。)

另外有一点就是,Gitea 内几乎所有链接都在使用基于 ROOT_URL 的绝对链接,所以基本绑死在这个 ROOT_URL 上,配置好后基本没办法用多个域名访问同一个 Gitea。准备使用内网穿透的用户要注意一下这个问题,很多内网穿透服务分配给用户的都是非标准端口,如果想在内外网都能良好访问自己的 Gitea 服务器,最好让 Gitea 内网的端口与公网端口一致,不然很多麻烦事情。

GitLab 会检测你用来访问 GitHub 所用的域名,而且很多地方都会根据这个更改显示,不会因为用不同于 external_url 的地址访问而出现问题,这方面问题会比 Gitea 少很多。 (注意一下,如果你在 external_url 中写了带端口号的地址,GitLab 的侦听端口也会跟着变更。不想改侦听端口的话记着覆盖 nginx['listen_port'] 设置)

隐私保护

隐私保护方面我觉得是 Gitea 最值得诟病的问题,也是我转而投向 GitLab 的主因。

Gitea 的一些功能需要 GitHub TOKEN 实现(譬如从 GitHub 导入私有项目等),GitHub TOKEN 作为用户隐私,本身应该受到良好保护,但我在实际使用过程中发现,目前版本(v1.16.4)的 Gitea 有严重的安全问题:

当用户正在进行使用 GitHub TOKEN 访问 GitHub 仓库的任务时,包含了 GitHub TOKEN 的 URL 直接明文出现在管理后台中,管理员可以轻松的从后台看到这些隐私信息:

img

这应该开发者考虑不周造成的问题,相对而言能明显感受到 GitLab 要更关心用户的隐私保护问题,涉及到隐私信息时都高度敏感,在不修改服务器本身的情况下,管理员也无法触及它们。(当然在管理员能接触到 GitLab 服务器的情况下,依然可以通过篡改服务器来窃取用户隐私,所以对第三方托管的服务器并不能无保留的信任。)

imgGitLab 中带有用户 TOKEN 的 URL 显示

功能

消息通知

GitLab 与 Gitea 都能配置邮件消息通知。

GitLab 每个用户都能设置自己接受的通知,或者完全拒绝邮件通知,设置的粒度可以细分到组/项目级别,管理员还能通过管理后台对用户手动群发邮件通知。

Gitea 的用户无法控制自己接受的通知,只能由管理员配置通知的类型,而且也只能进行全局范围的配置,无法细分到用户身上,而且所有通知都是 Gitea 的自动通知,管理员无法发送自定义通知。

对于 Gitea 这个邮件通知,不能说不能用,但对于多用户的服务器来说,我觉得难用到很难接受的程度,我在配好邮箱后尝试了一会就关掉了。

存储库导入与镜像

Gitea 和 GitLab 也都支持导入第三方 Git 仓库,特别是提供了原生的迁移 GitHub 仓库的办法,可以连带着 Issue、PR 等其他数据一同导入进来。

此项功能需要 GitHub TOKEN 来完成,Gitea 有泄露 TOKEN 的问题,这点在前面已经说过了,所以不建议在第三方托管的 Gitea 上进行此操作。

但如果在你自己的 Gitea 上执行,不需要担心隐私问题的话,我尝试下来的体验非常好,仓库内容基本都能原模原样地导入过来。

imgGitea 导入的 Issue

而 GitLab 的迁移功能个人体验就比较差了。Issue 虽然也能搬过来,但是无法做到 Gitea 这样保持创建者信息,所有的 Issue 创建者都会变成进行导入的用户,然后在内容中添加一条 Created by 信息来标识原创建者。

问题更大的是,GitLab 的 Issue Markdown 语法和 GitHub 有一定差别。最典型的问题是,GitHub Issue 中单个换行符就能换行,GitLab 则是保持了标准的 Markdown 语法,需要连续两个换行才可以,这导致导入的 Issue 格式全都乱成一团,根本没法看:

imgGitLab 导入后的样子

除此之外,Gitea 和 GitLab 还支持存储库镜像功能,能够让一个 Gitea/GitLab 存储库与一个外部的存储库(譬如 GitHub 上的存储库)保持关联。它们都支持这两种镜像模式:

  • Push 镜像:以当前仓库为主要仓库,在当前仓库发生修改后自动将修改推送到外部仓库中。
  • Pull 镜像:以外部仓库为主要仓库,在固定间隔后或者手动触发时从外部仓库拉取内容更新当前仓库中。

在镜像功能上,GitLab 很离谱的把 Pull 镜像归属到了 EE 功能中,也就是要付费才能使用,这一点我是完全没有想到的,因为这个功能怎么看都应该属于 CE 的范畴,这也是我对 GitLab CE 意见最大的地方。我自己部署的是 GitLab CE,所以无法尝试 Pull 镜像了。

GitLab 的 Push 镜像功能会在每次用户修改仓库或者手动触发时进行推送,我使用下来体验良好。

Gitea 的 Pull 镜像当然是完全能免费使用的,基本的定时与手动更新仓库功能都可用,就是可惜无法同时同步 wiki、Issue 和 PR。

而 Gitea 的 Push 镜像,我自己没有尝试过,但看文档的描述,Gitea 的 Push 镜像同步是定时触发的,我觉得这就挺迷惑的,还是 GitLab 的策略更好用。

而且特别要注意,Gitea 同步时唯一的认证方式是账号密码认证,但 GitHub 现在禁止账密认证,导致无法正常进行认证,唯一的解决方案是把 GitHub TOKEN 写在 URL 里,但除非是你自部署的 Gitea 并且其他人无法访问这个仓库,否则就会导致你的 GitHub TOKEN 泄露。

GitLab 原生就支持使用 GitHub TOKEN 或者通过 SSH 进行认证。SSH 不知道为什么我这里配好公钥也无法通过认证,但用 GitHub TOKEN 认证的方式工作一切正常,而且对 TOKEN 也有应有的保护,作为主要仓库使用并用它同步到 GitHub 上是没问题的。(SSH 地址必须是 ssh://git@github.com/<group name>/<repo name>.git 的形式,GitHub 的 Code 按钮里那个地址不能直接用,前面要补上 ssh://,中间的冒号也要改成正斜杠)

CI/CD

谈 Gitea 与 GitLab 的区别,那肯定少不了 CI/CD 这个重头戏。

Gitea 没有提供内置的 CI/CD 支持,但是可以用 Gitea 提供的 API 与其他 CI 集成,目前推荐的比较多的似乎是是自部署 Drone CI,但也可以与 Travis CI 这类现成的 CI 集成。

imgGitea 与 Drone CI 的集成

Gitea 与 CI 的集成我没有亲自尝试过,但可以参考上面 gitea.com 里现成的例子。我本来想尝试部署 JetBrains TeamCity,但 Gitea 目前的 API 并不足以与 TeamCity 集成,这在后续版本中可能会改进。

而 GitLab 原生就集成了一套强大的 CI 功能,而且就像 GitHub Action 与 GitHub 那样,它与 GitLab 有着极为紧密的结合。

GitLab 用于执行 GitLab CI 的程序叫做 GitLab Runner。在刚开始看文档的时候,我一直很疑惑为什么 GitLab Runner 的介绍在用户指南里,而非管理员的配置指南中,在配置好后我才豁然开朗,因为 GitLab 不止允许管理员注册全局可用的共享 GitLab Runner,它还允许一般用户为自己或者组注册自托管的 GitLab Runner 实例,让 CI 仅跑在自己的机器上。

目前我只是简单的配置并跑了一些简单的样例,尝试后我觉得很喜欢这样一套高度集成而且灵活易配置的 CI 方案,我认为这方面 GitLab 要比 Gitea强很多。

总结

根据到目前为止我自己的实际体验,对于仅个人或者小型团队内部的 Git 服务器来说,我更推荐 Gitea,它更轻量,更容易定制化,GitLab 相对来说太吃资源了,而且很多高级功能一般用户可能永远用不上。

如果是中大型团队/企业,或者是要搭建公开服务的站点,那么我只推荐 GitLab。Gitea 对于隐私的保护实在有很多欠缺,而且用起来的时候经常能感受到很多设计并不适合向大量用户提供稳定的服务。GitLab 虽然重,但是整体考虑更加完善,更适合作为商业化的产品使用。

目前我还没有来得及尝试更多功能,所以暂时也给不了更多建议,以后或许会继续更新踩坑经历,希望能帮到更多用户。

本文转载自: 知乎

乱码三千 – 点滴积累 ,欢迎来到乱码三千技术博客站

国内代码托管厂商汇总

发表于 2022-09-17

汇总如下

  1. Gitee

    点击进入

    开源中国旗下的产品, 算是国内老牌厂商了

  2. Coding.net

    点击进入

    目前属于腾讯旗下的产品

  3. CodeUp

    点击进入

    阿里云旗下的产品

  4. GitCode

    点击进入

    CSDN旗下的产品

  5. 小程序代码托管

    点击进入

    也是腾讯旗下的 主要用于微信小程序代码托管

  6. 极狐 JihuLab

    点击进入

    基于Gitlab搭建的托管平台

本文为作者原创转载时请注明出处 谢谢

乱码三千 – 点滴积累 ,欢迎来到乱码三千技术博客站

1…111213…50

乱码三千

android程序员一枚,擅长java,kotlin,python,金融投资,欢迎交流~

491 日志
143 标签
RSS
© 2025 乱码三千
本站总访问量次
由 Hexo 强力驱动
|
主题 — NexT.Muse v5.1.4
0%