众所周知,Telegram于5月底推出了官方的MTProto代理(又名MTProxy)服务器,该服务器使用
以下语言编写。 在2018年,没有Docker的地方不多,因为它伴随着零配置格式的相同“正式”
方式 。 一切都会好起来的,但是三个“ buts”却有点破坏了发行版的印象:图像重于> 130 Mb(有相当丰满的Debian,而不是通常的Alpine),由于“ zero-config”,它并不总是很方便地配置(仅通过环境设置)你们忘了竞选,布置了Dockerfile。
TL; DR我们将制作一个大小为5.94MB的,实际上是基于阿尔卑斯山的官方1:1官方docker镜像,并将其放在
此处 (和dockerfile放在
此处 ); 在此过程中,我们将弄清楚有时您如何可以使用Nippers和文件通过Alpine软件结交朋友,并且我们会玩一些游戏,只是为了娱乐。
图片内容
再一次,因为什么大惊小怪的? 让我们看看使用
history命令表示的官方图像是什么:
$ docker history --no-trunc --format "{{.Size}}\t{{.CreatedBy}}" telegrammessenger/proxy
从下至上分别读取层:

最厚的是Debian Jessie,从中继承了原始图像,我们必须首先删除它(高山:3.6,相比之下,它的重量为3.97MB); 其次是卷曲和新鲜证书。 要了解其他两个文件和目录的含义,我们将使用
run命令查看内部,用bash替换CMD(这将使您可以在启动的图像周围走动,更紧密地了解彼此,运行某些片段,复制有用的东西):
$ docker run -it --rm telegrammessenger/proxy /bin/bash
现在,我们可以轻松地恢复事件的图片-就像丢失的官方Dockerfile一样:
FROM debian:jessie-20180312 RUN set -eux \ && apt-get update \ && apt-get install -y --no-install-recommends curl ca-certificates \ && rm -rf /var/lib/apt/lists/* COPY ./mtproto-proxy /usr/local/bin RUN mkdir /data COPY ./secret/ /etc/telegram/ COPY ./run.sh /run.sh CMD ["/bin/sh", "-c", "/bin/bash /run.sh"]
如果mtproto-proxy是已编译的服务器,则secret文件夹仅包含带有AES加密密钥的hello-explorers-您正在做的文件(请参阅服务器命令,顺便说一句,官方建议通过API来获取密钥,但要这样写)可能是为了避免API也被阻止的情况),然后run.sh会为启动代理做所有准备工作。
组装方式
在Habré上已
收集的 CentOS 7 MTProxy下,我们将尝试在Alpine下收集映像,并在生成的docker映像中保存130兆字节的广告。
Alpine Linux的一个独特功能是使用musl而不是glibc。 两者都是标准的C库。 Musl很小(它没有“标准”的五分之一),但是体积和性能(至少是有希望的)决定了何时使用Docker。 而且将glibc放在Alpine上在种族上是不正确的,例如,Jakub Jirutka叔叔
不会理解 。
我们还将构建docker以隔离依赖关系并获得实验的自由,因此创建一个新的Dockerfile:
FROM alpine:3.6 RUN apk add --no-cache git make gcc musl-dev linux-headers openssl-dev RUN git clone --single-branch --depth 1 https://github.com/TelegramMessenger/MTProxy.git /mtproxy/sources RUN cd /mtproxy/sources \ && make -j$(getconf _NPROCESSORS_ONLN)
在依赖项中,git将派上用场(不仅用于克隆官方存储库,make文件还将sha提交附加到版本),make,gcc和头文件(通过经验获得最小集)。 我们只会克隆1次提交深度的master分支(我们绝对不需要历史记录)。 好吧,让我们尝试在使用-j开关进行编译时利用所有主机资源。 我故意将其分为多个层,以便在重建期间获得方便的缓存(通常有很多层)。
我们将运行
build命令(位于Dockerfile目录中):
$ docker build -t mtproxy:test .
这是第一个问题:
In file included from ./net/net-connections.h:34:0, from mtproto/mtproto-config.c:44: ./jobs/jobs.h:234:23: error: field 'rand_data' has incomplete type struct drand48_data rand_data; ^~~~~~~~~
实际上,所有后续的都将与之连接。 首先,对于那些不熟悉自己的人,编译器实际上发誓缺少drand48_data结构的声明。 其次,musl开发人员在线程安全的随机函数(带有_r后缀)和与其相关的所有事物(包括结构)上得分。 反过来,Telegram的开发人员也不必为未实现random_r及其对应物的系统进行编译(在许多OS库中,您可以看到HAVE_RANDOM_R标志或其任意+存在或不存在通常在自动配置器中存在的这组功能)。
好吧,现在我们一定要安装glibc吗? 不行 我们将从glibc复制所需的内容,并为MTProxy源制作补丁。
除了random_r的问题之外,我们还遇到了backtrace函数(execinfo.h)的问题,该函数用于在发生异常的情况下输出堆栈backtrace:您可以尝试使用libunwind中的实现替换它,但这是不值得的,因为调用是通过检查__GLIBC__。
将其放在./patches文件夹中,并稍微修改我们的Dockerfile以便即时应用补丁:
FROM alpine:3.6 COPY ./patches /mtproxy/patches RUN apk add --no-cache --virtual .build-deps \ git make gcc musl-dev linux-headers openssl-dev \ && git clone --single-branch --depth 1 https://github.com/TelegramMessenger/MTProxy.git /mtproxy/sources \ && cd /mtproxy/sources \ && patch -p0 -i /mtproxy/patches/randr_compat.patch \ && make -j$(getconf _NPROCESSORS_ONLN) \ && cp /mtproxy/sources/objs/bin/mtproto-proxy /mtproxy/ \ && rm -rf /mtproxy/{sources,patches} \ && apk add --no-cache --virtual .rundeps libcrypto1.0 \ && apk del .build-deps
现在,至少启动了组装好的mtproto-proxy二进制文件,我们可以继续进行。
清仓
现在是时候将原始run.sh转换为docker-entrypoint.sh了。 我认为,当“强制性绑定”进入ENTRYPOINT时(这总是可以从外部重载),并且启动dockerized应用程序的参数适合CMD中的最大值(+环境变量作为研究不足),这是合乎逻辑的。
我们可以在高山图像中安装bash和full grep(我将在后面解释),以避免头痛并按原样使用原始代码,但是它将使我们的微型图像膨胀到可耻的地步,因此我们将种植一个真正的他的母亲盆景。
让我们从shebang开始,将
#!/bin/bash
替换为
#!/bin/sh
。 高山灰的默认设置能够消化几乎所有bash的“原样”语法,但是我们仍然遇到一个问题-由于未知原因,他拒绝接受其中一种条件的括号,因此我们将通过反转比较逻辑来扩展它:

现在,我们正在等待grep的摊牌,在忙碌箱交付中,这与通常的摊派略有不同(顺便说一句,要慢得多,请记住您的项目)。 首先,他不理解表达式
{,15}
,他将必须明确指定
{0,15}
。 其次,它不支持
-P
标志(perl样式),但是在启用扩展(-E)时安静地摘要了表达式。
在我们的依赖项中,仅保留curl(没有用busybox中的wget替换它)和libcrypto(足够了,在此程序集中根本不需要直接使用openssl)。
几年前,一个漂亮的
多阶段构建出现在Docker中,例如,它非常适合Go应用程序或组装很复杂并且比最终清理更容易在图像之间传输工件的情况。 我们将用它来种植盆景,这将节省一些。
FROM alpine:3.6 # ( ) RUN apk add --no-cache --virtual .build-deps \ # ... , && make -j$(getconf _NPROCESSORS_ONLN) FROM alpine:3.6 # , , WORKDIR /mtproxy COPY --from=0 /mtproxy/sources/objs/bin/mtproto-proxy . # #
盆景应该是盆景-摆脱libcrypto安装。 构建时,我们需要openssl-dev包中的头文件,该文件在依赖项中将拉起libcrypto,而我们的可执行文件将使用libcrypto.so.1.0.0。 但这是唯一的依赖项,此外,它已预安装在Alpine中(在版本3.6中,它是libcrypto.so.41,3.7-libcrypto.so.42,它在/ lib /中)。 他们现在骂我,这不是最可靠的方法,但是值得,我们仍然在现有版本中添加符号链接(如果您有更好的方法,我很乐意接受PR)。
最后的修饰和结果:
Docker中心Github如有任何建议和贡献,我将不胜感激。