Wie jeder bereits
gehört hat , hat Telegram Ende Mai den offiziellen MTProto Proxy-Server (auch bekannt als MTProxy) gestartet, der in der
folgenden Sprache geschrieben ist . Im Jahr 2018 gibt es ohne Docker nicht viel, da es im Zero-Config-Format von demselben „offiziellen“
Weg begleitet wird. Alles wäre in Ordnung, aber drei "Aber" trübten den Eindruck der Veröffentlichung ein wenig: Das Bild wiegt> 130 MB (es gibt ein ziemlich pralles Debian, nicht das übliche Alpin), aufgrund der "Null-Konfiguration" ist es nicht immer bequem konfiguriert (nur durch die Umgebungseinstellungen). und die Jungs haben die Kampagne vergessen, legen die Docker-Datei aus.
TL; DR Wir werden ein praktisch 1-in-1-offizielles Docking-Image auf Alpenbasis mit einer Größe von 5,94 MB erstellen und
hier (und hier im Dockerfile) ablegen. Unterwegs werden wir herausfinden, wie Sie sich manchmal mit Zangen und einer Datei mit der Alpine-Software anfreunden können, und wir werden ein bisschen in der Größe spielen, ausschließlich zum Spaß.
Bildinhalt
Noch einmal, wegen was ist die ganze Aufregung? Mal sehen, was das offizielle Bild mit dem Befehl
history darstellt :
$ docker history --no-trunc --format "{{.Size}}\t{{.CreatedBy}}" telegrammessenger/proxy
Ebenen werden jeweils von unten nach oben gelesen:

Das dickste ist das Debian Jessie, von dem das Originalbild geerbt wurde. Wir müssen es zuerst loswerden (alpin: 3,6, zum Vergleich: 3,97 MB). gefolgt von Abmessungen sind Locken und frische Zertifikate. Um zu verstehen, was die beiden anderen Dateien und das Verzeichnis bedeuten, schauen wir uns den Befehl
run an und ersetzen CMD durch bash (auf diese Weise können Sie das gestartete Image umgehen, sich näher kennenlernen, bestimmte Fragmente ausführen und etwas Nützliches kopieren):
$ docker run -it --rm telegrammessenger/proxy /bin/bash
Jetzt können wir das Bild des Vorfalls problemlos wiederherstellen - so etwas wie das verlorene offizielle Dockerfile sah aus wie:
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"]
Wenn mtproto-proxy ein kompilierter Server ist, enthält der geheime Ordner nur die Datei "Hallo-Entdecker - wie geht es dir?" Mit dem AES-Verschlüsselungsschlüssel (siehe Serverbefehle, dort gibt es übrigens eine offizielle Empfehlung, den Schlüssel über die API abzurufen, aber so ausgedrückt wahrscheinlich, um die Situation zu vermeiden, in der die API ebenfalls blockiert ist) und run.sh alle Vorbereitungen zum Starten des Proxys trifft.
Der Inhalt der ursprünglichen run.sh Montage
Unter CentOS 7 MTProxy auf Habré, das bereits
gesammelt wurde , werden wir versuchen, ein Bild unter Alpine zu sammeln und Megabyte, Werbung, 130 im resultierenden Docker-Bild zu speichern.
Eine Besonderheit von Alpine Linux ist die Verwendung von Mussl anstelle von Glibc. Beide sind Standard-C-Bibliotheken. Musl ist winzig (es hat kein Fünftel des „Standards“), aber Volumen und Leistung (zumindest versprochen) entscheiden, wenn es um Docker geht. Und es ist nicht rassistisch korrekt, Glibc auf Alpine zu setzen, Onkel Jakub Jirutka
wird es zum Beispiel
nicht verstehen .
Wir werden auch Docker einbauen, um Abhängigkeiten zu isolieren und Freiheit zum Experimentieren zu gewinnen. Erstellen Sie also eine neue Docker-Datei:
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)
Von den Abhängigkeiten wird git nützlich sein (und nicht nur zum Klonen des offiziellen Repositorys, die make-Datei hängt das sha-Commit an die Version an), make-, gcc- und Header-Dateien (der Mindestsatz wurde empirisch ermittelt). Wir klonen den Master-Zweig nur mit einer Tiefe von 1 Commit (wir brauchen definitiv keinen Verlauf). Versuchen wir, beim Kompilieren mit dem Schalter -j alle Hostressourcen zu nutzen. Ich habe es absichtlich in eine größere Anzahl von Ebenen aufgeteilt, um ein bequemes Caching während des Wiederaufbaus zu erhalten (normalerweise gibt es viele davon).
Wir werden den Befehl
build ausführen (im Verzeichnis mit der Docker-Datei):
$ docker build -t mtproxy:test .
Und hier ist das erste Problem:
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; ^~~~~~~~~
Tatsächlich werden alle nachfolgenden damit verbunden. Erstens schwört der Compiler für diejenigen, die mit sich selbst nicht vertraut sind, auf das Fehlen einer Deklaration der Struktur drand48_data. Zweitens bewerteten musl-Entwickler threadsichere Zufallsfunktionen (mit dem Postfix _r) und alles, was mit ihnen verbunden ist (einschließlich Strukturen). Und die Entwickler von Telegram haben sich wiederum nicht darum gekümmert, für Systeme zu kompilieren, in denen random_r und seine Gegenstücke nicht implementiert sind (in vielen Betriebssystembibliotheken können Sie sehen, dass das HAVE_RANDOM_R-Flag oder das willkürliche + Vorhandensein oder Fehlen dieser Funktionsgruppe normalerweise im Autokonfigurator berücksichtigt wird).
Nun, jetzt werden wir definitiv glibc installieren? Nein! Wir werden das, was wir brauchen, von glibc auf ein Minimum kopieren und einen Patch für die MTProxy-Quellen erstellen.
Zusätzlich zu Problemen mit random_r haben wir ein Problem mit der Backtrace-Funktion (execinfo.h), mit der im Falle einer Ausnahme die Stack-Backtrace ausgegeben wird: Sie könnten versuchen, sie durch die Implementierung von libunwind zu ersetzen, aber es lohnt sich nicht, da der Aufruf durch Überprüfen auf gerahmt wurde __GLIBC__.
Random_compat.patch Patch-Inhalt Legen Sie es in den Ordner ./patches und ändern Sie unsere Docker-Datei ein wenig, um den Patch im laufenden Betrieb anzuwenden:
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
Jetzt wird zumindest die zusammengesetzte mtproto-proxy-Binärdatei gestartet, und wir können fortfahren.
Freigabe
Es ist Zeit, die ursprüngliche run.sh in docker-entrypoint.sh umzuwandeln. Meiner Meinung nach ist dies logisch, wenn die „obligatorische Bindung“ in ENTRYPOINT eingeht (sie kann immer von außen überladen werden) und die Argumente für den Start der Docker-Anwendung in CMD maximal passen (+ Umgebungsvariablen als Zweitbesetzung).
Wir könnten Bash und Full Grep in unser alpines Bild einbauen (ich werde es später erklären), um Kopfschmerzen zu vermeiden und den Originalcode so zu verwenden, wie er ist, aber es wird unser Miniaturbild zur Schande aufblasen, so dass wir einen echten Bonsai, seine Mutter, wachsen lassen.
Beginnen wir mit dem Shebang und ersetzen Sie
#!/bin/bash
durch
#!/bin/sh
. Die Standardeinstellung für alpine Asche ist in der Lage, fast die gesamte Bash-Syntax zu verarbeiten, aber wir stoßen immer noch auf ein Problem: Aus unbekannten Gründen lehnte er es ab, Klammern unter einer der Bedingungen zu akzeptieren. Daher werden wir sie durch Umkehren der Vergleichslogik erweitern:

Jetzt warten wir auf einen Showdown mit grep, der sich in der Busybox-Lieferung geringfügig von der üblichen unterscheidet (und übrigens viel langsamer ist, denken Sie bei Ihren Projekten daran). Erstens versteht er den Ausdruck
{,15}
, er muss
{0,15}
explizit angeben. Zweitens unterstützt es nicht das
-P
Flag (Perl-Stil), sondern verdaut den Ausdruck leise, wenn Extended (-E) aktiviert ist.
In unseren Abhängigkeiten bleibt nur Curl (es macht keinen Sinn, es durch wget aus der Busybox zu ersetzen) und libcrypto (es reicht aus, direkt openssl ist in dieser Assembly überhaupt nicht erforderlich).
Ein wunderschöner
mehrstufiger Build wurde vor einigen Jahren in Docker veröffentlicht. Er ist beispielsweise ideal für Go-Anwendungen oder für Situationen, in denen die Montage kompliziert ist und Artefakte einfacher von Bild zu Bild übertragen können als für die endgültige Bereinigung. Wir werden es verwenden, um unsere Bonsai zu pflanzen, dies wird ein wenig sparen.
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 . # #
Bonsai sollte Bonsai sein - entfernen Sie die libcrypto-Installation. Beim Erstellen benötigten wir die Header-Dateien aus dem openssl-dev-Paket, die in den Abhängigkeiten libcrypto aufrufen und unsere ausführbare Datei auf die Verwendung von libcrypto.so.1.0.0 ausrichten. Dies ist jedoch die einzige Abhängigkeit. Außerdem ist sie in Alpine vorinstalliert (in Version 3.6 ist sie libcrypto.so.41, 3.7 - libcrypto.so.42, sie befindet sich in / lib /). Sie schimpfen jetzt mit mir, dies ist nicht der zuverlässigste Weg, aber es lohnt sich und wir fügen der vorhandenen Version immer noch einen Symlink hinzu (wenn Sie einen besseren Weg haben, akzeptiere ich gerne PR).
Letzter Schliff und Ergebnis:
Docker HubGithubFür Ratschläge und Beiträge wäre ich dankbar.