中国国内からのアップグレードがgitの問題で失敗

Aliyun(Alibaba)の Ubuntu 20.04 サーバー上で Discourse インスタンスを運用しており、Git 関連のすべてと同様に、グレート・ファイアウォールに起因する問題に直面しています。launcher rebuild app を用いた手動アップグレードは、GnuTLS エラー(様々な種類)により、ほとんどの場合失敗します。これはサーバーにインストールされている Git のバージョンの問題ではなく、実際にはグレート・ファイアウォール内部のハンドシェイク処理に起因するものです。もちろん詳細は理解していませんが、複数の情報源がこの問題について詳しく議論しています。そのため、OpenSSL を使用して Git を手動でコンパイルするという選択肢もありません。

プル処理がコアを通過し、Docker Manager プラグインのクローン作成に成功することさえありますが、2〜3 つのプラグインのプル後に、タイムアウトや他のエラーが発生することが一般的です。

例:

$ ./launcher rebuild app
Ensuring launcher is up to date
Fetching origin
Launcher is up-to-date
Stopping old container
+ /usr/bin/docker stop -t 60 app
app
cd /pups && git pull && git checkout v1.0.3 && /pups/bin/pups --stdin
fatal: unable to access 'https://github.com/discourse/pups.git/': gnutls_handshake() failed: The TLS connection was non-properly terminated.
76630913bae18d6b45b6b3ecc3ec390c1e69222a493f2ecf424ee06adf9d1002
** FAILED TO BOOTSTRAP ** please scroll up and look for earlier error messages, there may be more than one.
./discourse-doctor may help diagnose the problem.

これも非常に一般的です:

fatal: unable to access 'https://github.com/discourse/discourse.git/': GnuTLS recv error (-54): Error in the pull function.

解決策 1
通常、GitHub からクローンする際は HTTPS ではなく SSH を使用すると、結果が良くなったり失敗しなくなったりします。しかし、Discourse 固有のリビルドタスクのため、ランチャーが HTTPS ではなく SSH を介してプルするように設定する場所がどこなのか全くわかりません。Discourse インスタンスをそのように設定することは可能でしょうか?

解決策 2
別の選択肢として、中国国内からブロックされたリソースにアクセスするために(アダルトサイトを見るため)使用している SOCKS5 プロキシを利用できます。Git は socks:// プロトコルを使用するように設定可能であることを知っていますが、Discourse 内でどのように、どこで設定を行うべきか理解していません。root ユーザーに対して git config --global で設定するのではなく、Discourse のリポジトリ固有の設定ファイルにこの情報を格納したいと考えています。これを達成する方法をご教示いただけますでしょうか?

この Discourse インスタンスはイントラネットで使用しており、現在では 1 ヶ月以上実質的に停止状態です。これは当然ながら、当社の運用に深刻な影響を及ぼしています。

「いいね!」 2

app.ymlenvセクションでプロキシ環境変数を渡すことで動作しますか?
また、GFW 下での Rubygem に関する解決策は以下の通りです:

Replace rubygems.org with taobao mirror to resolve network error in China をご覧になりましたか?

どうもありがとうございます。Ruby の gem は問題を引き起こしていません。ご投稿で触れられたテンプレートを最初から app.yml に組み込んでおり、それは完璧に機能しています。

問題は、メインのリポジトリとプラグインのリポジトリをクローンすることにあります。

Git フラグに関する環境変数の確認が必要ですが、残念ながら Docker、特に docker-compose ファイルには不慣れです。何か参考になる情報源をご存知でしょうか?

Discourse はご存知の通り docker-compose を使用していません。

before_web フックに以下のコマンドを追加することで動作するようになると思います。これは web.china.template.yml が行っていることと同様です。

git config --global http.proxy socks5://yourproxy:port

ビルド後にプロキシが不要になった場合は、以下のコマンドを after_web フックに追加してください。

git config --global --unset http.proxy

すべてのフックはコンテナ内で実行されるため、問題にはならないと思います。

「いいね!」 1
「いいね!」 2

Docker に関する私の無知のさらなる証拠ですね。はい、明らかに docker-compose ファイルではありません。これは「Docker ファイル」と呼ばれるのでしょうか?それともその用語は config.json を指すのでしょうか?まあ、とにかくあなたのアドバイスは正しい方向を示してくれました。ただ、フックの名前は before_web ではなく before_code と呼ぶべきでした。

要約すると:shadowsocks-libev で socks5 を設定し、localhost ではなくローカルマシンの 172.17.0.1 でリッスンし、あなたのメッセージにあるようにプロキシ情報を渡して、アプリを再構築してください。

この苦痛な経験をしている人が他にもいるだろうと思うので、ここで詳細なガイドを書くことにします。現時点では、テーマコンポーネントのリポジトリに関する問題に直面しているため、まだ rebuild は成功していませんが、少なくともすべてのプラグインのフェッチはクリアしました。

このトピックとは少し関係ありませんが、私が直面している問題はアプリを起動できないことではなく、別のマシンにある既存の redis-server 設定が、現在のアプリの状態の現実と一致していないことです。そのため、コンテナを起動して GUI を通じてテーマコンポーネントを無効化することができず、それらをクローンする際にタイムアウトが発生してしまいます。

ご丁寧に解説をご案内いただき、誠にありがとうございます。ただ、例が完全に一致しないため、いくつか補足させてください。

  1. これがわかりません、すみません?env コマンドを実行すると多くの情報が表示されますが、gitconfig に関連するものは何もありません。
  2. 1 が理解できないため、どの変数を渡すべきか見当がつきませんでした。また、app.ymlenv セクションに git flags を追加するのではなく、hook を介して呼び出しました。
  3. これは不要でした。コンテナ全体を SOCKS プロキシを通したくはなく、git fetch プロセスのみを通したいためです。ただし、この点はご参照いただいたスレッドの元のユースケースに特化したものであったのかもしれません。

それでも、ご助力いただきありがとうございました。おかげで正しい方向へ進むことができました。Discourse チームには大賛成です!:ok_hand:

「いいね!」 1

アリババクラウド(Aliyun)を中国本土内のリージョンでご利用になりましたか?

香港または国際版のアリババクラウドでは、この問題は発生しません。

「いいね!」 1

また、すでにこの詳細について議論されている可能性もありますが、見落としがある場合に備えて、OpenSSL を通じて Git をインストールするためのスクリプトを以下に紹介します。

中国からの手動アップグレードを楽に

手順

  1. 中国国外で SOCKS5 プロキシを作成
  2. 中国国内サーバーでプロキシ接続を設定・構成
  3. 編集を簡単にするためのテンプレートを作成
  4. テンプレートに Git プロキシ設定を追加
  5. app.yml にテンプレートを含める
  6. アプリを再構築

1 - リモート SOCKS5

使いやすさ(そして手頃な価格)を考慮し、シンガポールなどの地域に Digital Ocean サーバーをセットアップすることを推奨します。標準的な Ubuntu サーバーを使用し、SSH キーペア、UFW など、すべての基本的なセキュリティ要件の設定を完了した後、Shadowsocks をインストールします。

リモートマシン上
$ sudo apt install shadowsocks-libev

プロキシ設定を構成します。

$ cd /etc/shadowsocks-libev

# 元のファイルを保持するのが好きなので
$ sudo cp config.json orig.config.json
$ sudo nano config.json

timeoutmethod に特に注意してください。

{
    "server":"123.123.123.123", # リモートサーバーの IP
    "server_port":8400, # お好みで
    "local_port":1080,
    "password":"Swordfish", 
    "timeout":600, # <= 必須!
    "method":"chacha20-ietf-poly1305"
}

systemd 設定(/lib/systemd/system/shadowsocks-libev-local@.service)内のすべての設定をダブルチェックしてください。shadowsocks-libev-local@.service を有効にし、再起動して、サービスが実行されているか確認します。

2 - 中国国内サーバーでのプロキシ接続設定

Discourse マシン上

$ sudo apt install shadowsocks-libev

Aliyun を使用している場合は、彼らの奇妙なコンソール内のファイアウォール設定を検索し、それぞれのポート設定を確認してください。

クライアントマシンで systemd 設定をいじくり回す必要はありませんが、Docker 用と通常の使用用の設定ファイルを分けて保持してください。Docker のコンテキスト外でも SOCKS5 プロキシを使用する可能性があるため、Docker でアクセス可能なネットワークアドレスの代わりに 127.0.0.1 を使用したい場合があるからです。

$ cd /etc/shadowsocks-libev
$ sudo cp config.json local.json
$ sudo cp config.json docker.json

設定を以下のように適応させます。

$ sudo nano local.json

{
    "server":["123.123.123.123"], # リモートマシンの IP
    "mode":"tcp_and_udp", # 私のセットアップでは異なるバージョンの shadowsocks-libev があるため、この注釈が異なります
    "server_port":8400,
    "local_address":"127.0.0.1",
    "local_port":1080,
    "password":"Swordfish",
    "timeout":600, # <= これを確認してください
    "method":"chacha20-ietf-poly1305"
}

便宜上、.bashrc にエイリアスを追加しましょう。

$ nano ~/.bashrc

# 貼り付け
alias dockershadow='ss-local -c /etc/shadowsocks-libev/local.json'

Docker がホストマシンのネットワークを通過できるように、もう一方の設定も適応させます。

$ sudo nano docker.json

{
    "server":["123.123.123.123"],
    "mode":"tcp_and_udp",
    "server_port":8400,
    "local_address":"172.17.0.1",
    "local_port":1080,
    "password":"Swordfish",
    "timeout":600,
    "method":"chacha20-ietf-poly1305"
}

Docker 固有の設定を使用するためのエイリアスを設定します。

alias dockershadow='ss-local -c /etc/shadowsocks-libev/docker.json'

3 & 4 - app.yml を整理するためのテンプレート作成

これは完全にオプションであり、好みに依存します。私は app.yml を読みやすく短く保ち、代わりにコンポーネントを別の場所で管理することを好みます。名前は好みに合わせて付けられますが、私は web.git.template.yml にしました。

$ nano templates/web.git.template.yml
# 貼り付け:

hooks:
  before_code:
    - exec:
       cmd:
         - git config --global http.proxy socks5://172.17.0.1:1080
         - git config --global https.proxy socks5://172.17.0.1:1080
         - git config --global https.sslVerify = false 

# オプション
  after_code:
    - exec:
       cmd:
         - git config --global --unset http.proxy
         - git config --global --unset https.proxy
         - git config --global --unset https.sslVerify

私は after_web フックでテストしましたが、それはうまくいきませんでした。

5 - app.yml の適応

app.yml でテンプレートを呼び出します。

$ cd /<discourse dir>
$ sudo nano containers/app.yml


templates:
  - "templates/web.template.yml"
  - "templates/web.china.template.yml"
  - "templates/web.ratelimited.template.yml"
  - "templates/web.socketed.template.yml"
  - "templates/web.git.template.yml"

テンプレートセクションは多分異なる表示になっているでしょうが、web.chinaweb.git-blabla(またはあなたが付けた名前)のテンプレートを含めるようにしてください。app.yml1080:1080公開しないでください

6 - 再構築

再構築する前に、Git でのクローン時にプロキシ設定が機能しているか確認してください。

$ git config --global http.proxy socks5://172.17.0.1:1080
$ git config --global https.proxy socks5://172.17.0.1:1080
$ git config --global https.sslVerify = false 

もちろん、これによりユーザーのホームディレクトリにある .gitconfig にプロキシフラグが追加されますので、テスト後に削除するよう注意してください。
GitHub 上の多数のファイルを持つランダムな大きなリポジトリを選択し、クローン速度を確認してください。設定が正しければ、Aliyun のセットアップにもよりますが、約 12〜15 MB/s でクローンできるはずです。接続速度が 200 KB/s から徐々に約 10 MB/s まで上昇する場合は、努力は失敗しています。

最後に再構築します。

$ cd /<discourse directory>

# 以前設定したエイリアスを使用してプロキシを実行
$ dockershadow
$ ./launcher rebuild app

再構築プロセスは頻繁に失敗するため、根気(そしておそらく白酒)が必要です。app.yml に設定されているプラグインが少ないほど、再構築が成功する可能性が高くなります。

7 - 備考

私はこれをまだ 本番環境対応 の手順ではなく、単なる回避策と考えています。そのため、GitHub リポジトリを中国国内でミラーリングする方法について、誰かがアイデアを持っているかもしれません。そうすれば、この作業がもう少し楽になるでしょう。ご存知の通り、GFW 内部の不透明なメカニズムは絶えず変化しています。

もちろん、SOCKS5 プロキシは多くの選択肢の一つに過ぎませんが、私は多目的なソリューションを手にしたいと考えています。

もし誰かがこの回避策を本番環境対応にするアイデアを持っているなら、あなたの意見をお待ちしています。Discourse は素晴らしいソフトウェアですが、中国で広く使用されていない理由の一つは、面倒なインストールとメンテナンスプロセスだと推測します。過去 1 年間は、nGinx リバースプロキシで設定したタイムアウト設定に関係なく、GUI 経由でのアップグレードは 100% 失敗しました。

中国語翻訳は後ほど掲載します

「いいね!」 7

その通りです。このインスタンスの主な目的が社内イントラネットフレームワークの一部となることであるため、レイテンシの問題により残念ながら香港は選択肢になりません。また、(近々登場する)顧客向けインスタンスは中国本土のユーザーを対象とする予定です(WeChatの認証方法を確立し次第)。そのため、中国本土のアリババクラウドゾーンで機能する解決策が必要です。

ありがとうございます。いくつかのガイドを確認しましたが、この問題の主な原因は Git の TLS 認証そのものではなく、GFW のパケット検査プロセスにおけるハンドシェイクのチェックにあるため、このアプローチは見送りました。openssl を使って git をコンパイルすると、私が読んだところによると、新しい世界への扉が開き、そこには苦痛が待ち受けているとのことでした。

多くのテーマコンポーネントは、ビルド時(あるいはコンテナ起動時)に GitHub から取得されます。そのため、git プロキシを追加するための別のフックが存在し、それが役立つ可能性があります。GUI との連携を維持したい場合は、プロキシを削除しないでください。また、redis-server が原因ではないようです。

redis-server は、再構築の失敗に複雑さを加えた単なる別の問題でした。ある種のループ状態でした:外部の redis 設定が変更された一方で、再構築前のアプリの状態は、その特定の redis 設定でなければ起動できませんでした。しかし、テーマコンポーネントの取得が機能しなかったため、再構築できませんでした。
ただ、幸運にも 20〜20 回ほどの再構築実行を経て、ようやくテーマコンポーネントの更新が取得されました。

アプリ全体の設計の文脈では、「セーフモード」での再構築方法、つまりプラグインやテーマに依存せずにアプリを再構築する方法についてのドキュメントがあると良いと思います。テーマコンポーネントを処理するフック、あるいはプラグインをアンインストールではなく無効化する方法が見つからず、がっかりしました。

編集:わあ、今になってセーフモードへのリンクに気づきました。以前は見つけられませんでした(中国では Google が使えないので、Bing で関連する * anything * を探すしかありません)。なんてこと、あれがあればかなり助かったでしょう!

つまり、Discourse with DO managed Redis - #3 by Falco のようなマネージド Redis サーバーを指定したが、再構築に失敗したということですか?

Redis の問題は二次的なものでしたが、全体的な Git の問題に大きな複雑さを加えました。上記の私の詳細な投稿から分かる通り、私はこれらの問題を解決しました。

はい、最初から分散型 Redis クラスターを Discourse に接続していました。ただし、これは管理されておらず、他のマシン上にあります。

Redis サーバーへの接続失敗によりアプリが起動しなかったため、GUI でテーマコンポーネントを無効化できませんでした。
新しい Redis 設定を適用するにはアプリの再構築が必要でしたが、GitHub リポジトリからの取得失敗により行うことができませんでした。

https://meta.discourse.org/t/a-fork-of-discourse-docker-repo-for-china

「いいね!」 1

HTTPプロキシ設定を追加しても問題が発生した場合、

GnuTLS recv error (-110): The TLS connection was non-properly terminated.

元のソリューションに加えて、テンプレートに以下のpostBufferプロパティを追加すると問題が解決します。gnutls-binのインストールが必要です。

hooks:
  before_code:
    - exec:
       cmd:
         - apt-get update -y
         - apt-get install -y gnutls-bin
         - git config --global http.proxy socks5://172.17.0.1:1080
         - git config --global https.proxy socks5://172.17.0.1:1080
         - git config --global https.sslVerify false
         - git config --global http.postBuffer 1048576000

# optional
  after_code:
    - exec:
       cmd:
         - git config --global --unset http.proxy
         - git config --global --unset https.proxy
         - git config --global --unset https.sslVerify
         - git config --global --unset http.postBuffer
「いいね!」 2