Docker、まだ誰も聞いていない場合-コンテナ仮想化を管理するためのオープンソースフレームワーク。 速く、快適で、思慮深く、ファッショナブルです。 実際、彼は、サーバー構成の管理、アプリケーションの構築、サーバーコードの実行、依存関係の管理などの高貴な作業でゲームのルールを変更します。
Dockerが推奨するアーキテクチャは、それぞれが単一のコマンドを実行する分離されたコンテナーです。 これらのコンテナは、互いを見つける方法のみを知っている必要があります。つまり、コンテナのfqdnとポート、またはipとポート、つまり外部サービスに関する情報のみを知る必要があります。
このような座標をDockerで実行されているプロセスの内部に伝える推奨される方法は、環境変数です。
NODE_ENV
は適用されないこのアプローチの典型的な例は、Railsフレームワークで採用されている
DATABASE_URL
または
NODE_ENV
フレームワークで採用されているNODE_ENVです。
そして、コンテナ内のアプリケーションがデータベースを便利かつ制約なく見つけることを可能にする環境変数があります。 ただし、このためには、アプリケーションを作成する人がそれについて知っている必要があります。
環境変数を使用したアプリケーションの
構成は適切で正しいものですが、アプリケーションの記述が不十分な場合があり、何らかの方法で実行する必要があります。
Docker、環境変数およびリンク
2つのコンテナーをリンクし、Dockerリンクメカニズムを提供する場合、Dockerが役立ちます。 それらについての詳細
はDockerのサイトのマニュアルで読むことができますが、要するに次のようになります:
- 起動時にコンテナに名前を付け
docker run -d --name db training/postgres
: docker run -d --name db training/postgres
。 これで、 db
という名前のこのコンテナを参照できます。 - 2番目のコンテナーを開始し、最初のコンテナーに関連付け
docker run -d -P --name web --link db:db training/webapp python app.py
この行で最も興味深いのは、-- --link name:alias
です。 name
はコンテナの名前、 alias
はこのコンテナがランナーに知られる名前です。 - これにより、2つの結果がもたらされます:最初に、
db
コンテナーを指すweb
コンテナーに一連の環境変数が表示され、次に、データベースコンテナーを開始したipを指すweb
コンテナーの/etc/hosts
コンテナーにエイリアスdb
が表示されます。 web
コンテナで使用できる環境変数のセットは次のとおりです。
DB_NAME=/web/db DB_PORT=tcp:
そして、アプリケーションがそのような変数を読む準備ができていない場合、
socat
consoleユーティリティが助けになります。
socat
socat
は、Unixポート転送ユーティリティです。 アイデアは、その助けを借りて、コンテナ内のアプリケーションの印象を作成することです。たとえば、開発者のコンピュータで発生するように、データベースが同じホストとその標準ポートの同じコンテナで実行されているという印象です。
socat
、すべての低レベルUnixと同様、非常に軽量であり、コンテナのメインプロセスに負担をかけません。
リンク機構がコンテナにスローする環境変数を詳しく見てみましょう。 特に興味深いのは、
DB_PORT_5432_TCP=tcp://172.17.0.5:5432
です。 この変数には、必要なすべてのデータが含まれます:localhost(
DB_5432_TCP
5432)でリッスンするポートと、データベース自体の座標(172.17.0.5:5432)。
このような変数は、データベース、
Redis
および補助サービスの各送信リンクのコンテナーにスローされます。
次のようにコマンドをラップするスクリプトを作成します。目的の環境変数のリストをスキャンし、それぞれに対してsocatを実行し、転送されたコマンドを実行して制御を与えます。 スクリプトが終了すると、すべてのsocatプロセスが完了するはずです。
スクリプト
標準ヘッダー。
set -e
は、最初のエラーでスクリプトを完了するようシェルに指示します。つまり、通常のプログラマーの動作が必要です。
#!/bin/bash set -e
追加のsocatプロセスを生成するため、それらを監視して、後で完了し、完了するまで待機できるようにする必要があります。
store_pid() { pids=("${pids[@]}" "$1") }
これで、記憶できる子プロセスを生成する関数を作成できます。
start_command() { echo "Running $1" bash -c "$1" & pid="$!" store_pid "$pid" } start_commands() { while read cmd; do start_command "$cmd" done }
アイデアは
(_,_,_)
環境変数のセットからタプル
(_,_,_)
を
_TCP
、それらを
socat
起動コマンドのセットに
socat
です。
to_link_tuple() { sed 's/.*_PORT_\([0-9]*\)_TCP=tcp:\/\/\(.*\):\(.*\)/\1,\2,\3/' } to_socat_call() { sed 's/\(.*\),\(.*\),\(.*\)/socat -ls TCP4-LISTEN:\1,fork,reuseaddr TCP4:\2:\3/' } env | grep '_TCP=' | to_link_tuple | sort | uniq | to_socat_call | start_commands
env
は環境変数のリストを表示し、
grep
は必要なもののみを残し、
to_link_tuple
必要なトリプルを引き出し
sort | uniq
sort | uniq
1つのサービスに対して2つの
socat
の起動
sort | uniq
防ぎます
to_socat_call
は必要なコマンドをすでに作成します。
また、メインプロセスが完了したときに
socat
子プロセスを完了したいと考えました。 これを行うには、
SIGTERM
送信します。
onexit() { echo Exiting echo sending SIGTERM to all processes kill ${pids[*]} &>/dev/null } trap onexit EXIT
exec
コマンドでメインプロセスを開始します。 その後、制御が彼に転送され、彼の
STDOUT
が表示され、彼は
STDIN
信号を受信し
STDIN
。
exec "$*"
スクリプト全体を
1つのピースで表示できます。
それで何?
このスクリプトをコンテナー(たとえば、
/run/links.sh
/
/run/links.sh
入れ、次のように
/run/links.sh
を開始します。
$ docker run -d -P
出来上がり! ポート
5432
127.0.0.1
のコンテナでは、postgresが利用可能になります。
エントリーポイント
スクリプトについて覚えておく必要がない
ように、DockerfileのENTRYPOINTディレクティブを使用して 、イメージをエントリポイントに設定できます。 これにより、このようなイメージで起動されたコマンドは、最初にこのエントリポイントの形式のプレフィックスで補完されるという事実につながります。
Dockerfile
追加します。
ADD ./links.sh /run/links.sh ENTRYPOINT ["/run/links.sh"]
繰り返しますが、コンテナはコマンドを渡すだけで起動でき、関連付けられたコンテナのサービスがローカルホストで実行されているかのようにアプリケーションに表示されることを確認します。
そして、画像へのアクセスがない場合はどうなりますか?
上記に関連して、興味深い問題があります。画像内にアクセスがない場合に、サービスの同じ便利なプロキシを作成する方法は? つまり、彼らはイメージを与えて、内部に
socat
があることを誓いますが、スクリプトはそこになく、添付することはできません。 しかし、起動チームをarbitrarily意的に複雑にすることができます。 ラッパーを内部にスローする方法は?
コンテナ内のホストファイルシステムの一部を転送する機能が役立ちます。 つまり、たとえば、ホストファイルシステムに
/usr/local/docker_bin
フォルダーを
/usr/local/docker_bin
、そこに
links.sh
て、次のようにコンテナーを起動できます。
$ docker run -d -P \ --name web \ --link db:db training/webapp \ -v /usr/local/docker_bin:/run:ro \ /run/links.sh python app.py
その結果、
/usr/local/docker_bin
配置したスクリプトは、コンテナー内で実行可能になります。
roフラグを使用したことに注意してください。これは、コンテナが
/run
フォルダーに書き込むことを許可しません。
別の方法は、イメージから継承し、そこにファイルを追加するだけです。
合計
socat
と良い単語を使用すると、良い単語を単独で使用するよりもはるかに便利な方法でコンテナ間で通信できます。
あとがきの代わりに
気配りのある洗練された読者であれば、
アンバサダードライブラリが原則として同じことを行っていることに気付くでしょう。 そして、この読者は絶対に正しいでしょう。 システムを動作させるだけのユーザーは、おそらく既成の実績のあるソリューションを使用することを好むでしょうが、Habrはそのようなユーザーの間ではあまり人気がありません。 だからこそ、このオプスが生まれました。これは、良いジョークのように、明白なことを伝えるだけでなく、教えています。
ご清聴ありがとうございました。