Docker゚クスペリ゚ンス

序文の代わりに





今日、私は倢を芋たした。たるで数匹の倧きさに刺されたかのように
キロバむト、䜕らかの皮類の゜ケットで立ち埀生し、コンテナヌで起動したす。
オヌバヌレむネットワヌクに割り圓おられ、蚱可されたトランスポヌト
他のコンテナでのサヌビスのテスト...
ただdocker rmを実行しおいたせん


少し前たで、私は非垞にクヌルなチヌムのメンバヌになれたこずは幞運でした
Centos-admin.ruで 、私のような人々ず出䌚いたした。新しいテクノロゞヌ、愛奜家、そしおただ玠晎らしい人たちに情熱を持っおいる志を同じくする人々。 そのため、すでに2日目に同僚ず私は「ドッキング可胜なものをすべおドッキングする」必芁がある1぀のプロゞェクトに取り組たれたした。サヌビスの高可甚性を確保するこずは非垞に重芁でした。

それたでは、私は普通のLinuxベヌスのルヌム管理者でした。すぐに、皌働時間、apt-get-installedパッケヌゞ、構成ルヌル、再起動サヌビス、タむルログを枬定したした。 䞀般的に、圌は特に優れた実甚的なスキルを持っおいたせんでした;圌はペット察の抂念に぀いお党く䜕も知りたせんでした。 牛は 、Dockerに実質的になじみがなく、䞀般的に、圌がどのような機䌚を隠しおいるのかに぀いおほずんど知りたせんでした。 そしお自動化ツヌルから、サヌバヌずさたざたなbashスクリプトを構成するためにansibleのみを䜿甚したした。



このプロゞェクトでの䜜業䞭に埗た経隓に基づいお、少し共有したいず思いたす。



Docker化されたクラスタヌが解決する必芁があるタスク


-動的むンフラストラクチャ。
-倉曎の迅速な実装。
-アプリケヌションの展開の簡玠化。

䜿甚されたツヌル


-ドッカヌ
-Docker swarm゚ヌゞェント+管理
-領事
-登録者
-領事テンプレヌト
-Docker䜜成
-手

ツヌルの説明



Docker





Habrを含むDockerに関する蚘事はすでにたくさんありたした。 それが䜕であるかを詳现に説明すべきではないず思いたす。
すべおの人の生掻を簡玠化するツヌル。 開発者、テスタヌ、システム管理者、アヌキテクトに。
Dockerを䜿甚するず、ほがすべおのアプリケヌションをほがすべおのプラットフォヌムで䜜成、実行、展開できたす。
Dockerはgitず比范できたすが、コヌドを操䜜するコンテキストではなく、アプリケヌション党䜓を操䜜するコンテキストで比范できたす。

ここでは、この玠晎らしい補品の喜びに぀いお倚くを話すこずができたす。

Docker swarm





Swarmは、すべおのホストノヌドを1぀のクラスタヌに論理的に結合する機胜を提䟛したす。
これは、どのノヌドでこのコンテナたたはそのコンテナを実行するかを考える必芁がないように機胜したす。 Swarmは私たちのためにそれを行いたす。 アプリケヌションを「どこか」で起動したいだけです。
Swarmの操䜜-コンテナヌのプヌルを操䜜したす。 SwarmはDocker APIを䜿甚しおコンテナを操䜜したす。

通垞、コマンドラむンで䜜業する堎合、倉数を指定するず䟿利です
export DOCKER_HOST=tcp://<my_swarm_ip>:3375 

そしお、通垞どおりdockerコマンドを䜿甚したすが、すでにロヌカルノヌドではなく、クラスタヌ党䜓で機胜しおいたす。

--labelオプションに泚意しおください。 これを䜿甚しお、ノヌドのノヌトを指定できたす。 たずえば、SSDディスクを搭茉したマシンがあり、PosrgreSQLを䜿甚しおコンテナを起動する必芁がある堎合、クラスタヌ内の「どこか」ではなく、高速ディスクがむンストヌルされおいるノヌド䞊にありたす。

ノヌドデヌモンにラベルを割り圓おたす。
 docker daemon --label com.example.storage="ssd" 

指定されたラベルのフィルタヌでPostgreSQLを開始したす。
 docker run -d -e constraint:com.example.storage="ssd" postgres 


フィルタヌの詳现

Swarmクラスタのstartegyなどのパラメヌタも怜蚎する䟡倀がありたす。 このパラメヌタヌを䜿甚するず、クラスタヌのノヌド間で負荷をより効率的に分散できたす。
3぀の戊略パラメヌタヌをノヌドに割り圓おるこずができたす 。

-スプレッド
他の戊略パラメヌタヌが指定されおいない堎合、デフォルトで䜿甚されたす。 この堎合、このノヌドで実行されおいるコンテナが他のノヌドよりも少ない堎合、swarmは新しいコンテナを起動したす。 このパラメヌタヌは、コンテナヌの状態を考慮したせん。 すべお停止するこずもできたすが、このノヌドは新しいコンテナを開始するために遞択されたせん。

-ビンパック
反察に、このパラメヌタヌを䜿甚するず、swarmは、県球ぞのコンテナヌで各ノヌドを詰たろうずしたす。 停止したコンテナもここで考慮されたす。

-ランダム
名前はそれ自䜓を物語っおいたす。

領事





領事は、ミッチェル橋本のギャング、 ハシコヌプの別の玠晎らしい補品であり、Vagrantや他の倚くのような玠晎らしいツヌルで私たちを喜ばせたす。
Consulは、登録者によっお最新の状態に維持される分散型の䞀貫した構成リポゞトリずしお機胜したす。
゚ヌゞェントずサヌバヌで構成されたすN / 2 + 1サヌバヌのクォヌラム。 ゚ヌゞェントはクラスタヌのノヌドで起動され、サヌビスの登録、怜蚌スクリプトの実行、およびConsulサヌバヌの結果の報告に関䞎したす。
Consulをキヌ倀ストアずしお䜿甚しお、コンテナの関係をより柔軟に構成するこずもできたす。
たた、Consulは、登録者もサポヌトしおいるチェックのリストに埓っおヘルスチェッカヌずしお機胜したす。
サヌビス、チェック、ノヌド、そしおもちろんREST APIのステヌタスを衚瀺できるWeb UIがありたす。

チェックに぀いお少し

スクリプト

スクリプトチェック。 スクリプトはステヌタスコヌドを返す必芁がありたす。

-終了コヌド0-合栌のステヌタスをチェックむンしたす぀たり、サヌビスはすべお正垞です
-終了コヌド1-譊告ステヌタスのチェックむン
-その他のコヌド-倱敗ステヌタスを確認する

䟋
 #!/usr/bin/with-contenv sh RESULT=`redis-cli ping` if [ "$RESULT" = "PONG" ]; then exit 0 fi exit 2 


ドキュメントには、nagiosプラグむンに䌌たものの䜿甚䟋も蚘茉されおいたす。
 { "check": { "id": "mem-util", "name": "Memory utilization", "script": "/usr/local/bin/check_mem.py", "interval": "10s" } } 


gist.github.com/mtchavez/e367db8b69aeba363d21

TCP

指定されたホスト名/ IPアドレスの゜ケットをノックしたす。 䟋
 { "id": "ssh", "name": "SSH TCP on port 22", "tcp": "127.0.0.1:22", "interval": "10s", "timeout": "1s" } 


HTTP

暙準HTTPチェックの䟋

REST API Consulを介しおチェックを登録するこずに加えお、-l label 匕数を䜿甚しお、コンテナヌの開始時にチェックをハングさせるこずができたす。
䟋ずしお、django + uwsgiを䜿甚しおコンテナを起動したす。
 docker run -p 8088:3000 -d --name uwsgi-worker --link consul:consul -l "SERVICE_NAME=uwsgi-worker" -l "SERVICE_TAGS=django" \ -l "SERVICE_3000_CHECK_HTTP=/" -l "SERVICE_3000_CHECK_INTERVAL=15s" -l "SERVICE_3000_CHECK_TIMEOUT=1s" uwsgi-worker 


Consul UIには、暙準のdjangoペヌゞのヘッダヌが衚瀺されたす。 チェックステヌタスが合栌であるこずがわかりたす。これは、すべおがサヌビスで正垞であるこずを意味したす。



たたは、http経由でREST APIにリク゚ストを行うこずができたす。
 curl http://<consul_ip>:8500/v1/health/service/uwsgi-worker | jq . 

 [ { "Node": { "Node": "docker0", "Address": "127.0.0.1", "CreateIndex": 370, "ModifyIndex": 159636 }, "Service": { "ID": "docker0:uwsgi-worker:3000", "Service": "uwsgi-worker", "Tags": [ "django" ], "Address": "127.0.0.1", "Port": 8088, "EnableTagOverride": false, "CreateIndex": 159631, "ModifyIndex": 159636 }, "Checks": [ { "Node": "docker0", "CheckID": "serfHealth", "Name": "Serf Health Status", "Status": "passing", "Notes": "", "Output": "Agent alive and reachable", "ServiceID": "", "ServiceName": "", "CreateIndex": 370, "ModifyIndex": 370 }, { "Node": "docker0", "CheckID": "service:docker1:uwsgi-worker:3000", "Name": "Service 'uwsgi-worker' check", "Status": "passing", "Notes": "", "Output": "", "ServiceID": "docker0:uwsgi-worker:3000", "ServiceName": "uwsgi-worker", "CreateIndex": 159631, "ModifyIndex": 159636 } ] } ] 


HTTPサヌビスが2xx応答ステヌタスを返す限り、Consulはそれが生きおいるず芋なしたす。 応答コヌドが429芁求が倚すぎるの堎合-怜蚌は譊告状態になり、他のすべおのコヌドは倱敗ずしおマヌクされ、Consulはこのサヌビスを倱敗ずしおマヌクしたす。
デフォルトでは、httpチェック間隔は10秒です。 タむムアりトパラメヌタを定矩するこずにより、異なる間隔を指定できたす。
Consul Templateは、怜蚌の結果に基づいお、バランサヌに構成ファむルを生成したす。バランサヌはN番目の「正垞な」ワヌカヌを䜿甚し、バランサヌはワヌカヌにリク゚ストを送信したす。

領事ぞの新しい小切手の登録
 curl -XPUT -d @_ssh_check.json http://<consul_ip>:8500/v1/agent/check/register 


ssh_check.jsonファむルの怜蚌パラメヌタヌは次のずおりです。
 { "id": "ssh", "name": "SSH TCP on port 22", "tcp": "<your_ip>:22", "interval": "10s", "timeout": "1s" } 


チェックを無効にしたす。
 curl http://<consul_ip>:8500/v1/agent/check/deregister/ssh_check 


Consulの可胜性は非垞に倧きく、残念ながら1぀の蚘事でそれらすべおを網矅するこずは問題です。
垌望する人は、倚くの䟋があり、すべおに぀いお十分に曞かれおいる公匏ドキュメントを参照できたす。

登録者



登録者は、実行䞭のDockerコンテナヌの倉曎に関する情報提䟛者ずしお機胜したす。 コンテナのリストを監芖し、コンテナを起動たたは停止する堎合にConsulに適切な倉曎を加えたす。 登録者は、新しいコンテナの䜜成を含めお、すぐにConsulのサヌビスのリストに反映したす。
たた、コンテナメタデヌタに基づいおヘルスチェック゚ントリをConsulに远加したす。
たずえば、次のコマンドでコンテナを起動する堎合
 docker run --restart=unless-stopped -v /root/html:/usr/share/nginx/html:ro --links consul:consul -l "SERVICE_NAME=nginx" -l "SERVICE_TAGS=web" -l "SERVICE_CHECK_HTTP=/" -l "SERVICE_CHECK_INTERVAL=15s" -l "SERVICE_CHECK_TIMEOUT=1s" -p 8080:80 -d nginx 


登録者はnignxサヌビスをConsulに远加し、このサヌビスのHTTPチェックを䜜成したす。

詳现

領事テンプレヌト



Hashicorpから来たもう1人のすばらしいツヌル。 Consulに倉わり、その䞭にあるパラメヌタヌ/倀の状態に応じお、たずえばコンテナヌ内などのテンプレヌトに埓っおファむルのコンテンツを生成できたす。 Consul Templateは、Consulでデヌタを曎新するずきにさたざたなコマンドを実行するこずもできたす。
䟋

NGINX

server.conf.ctmplファむルを䜜成したす
 upstream fpm { least_conn; {{range service "php"}}server {{.Address}}:{{.Port}} max_fails=3 fail_timeout=60 weight=1; {{else}}server 127.0.0.1:65535{{end}} } server { listen 80; root /var/www/html; index index.php index.html index.htm; server_name your.domain.com; sendfile off; location / { } location ~ \.php$ { fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name; fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_pass fpm; fastcgi_index index.php; include fastcgi_params; } } 

Consulテンプレヌトを実行したす。
 consul-template -consul <your_consul_ip>:8500 -template server.conf.ctmpl -once -dry 

-dryパラメヌタヌは結果の構成をstdoutに衚瀺し、-onceパラメヌタヌはconsul-templateを1回実行したす。
 upstream fpm { least_conn; server 127.0.0.1:9000 max_fails=3 fail_timeout=60 weight=1; } server { listen 80; root /var/www/html; index index.php index.html index.htm; server_name your.domain.com; sendfile off; location / { } location ~ \.php$ { fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name; fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_pass fpm; fastcgi_index index.php; include fastcgi_params; } } 

ご芧のずおり、ConsulにphpずいうIPアドレスずサヌビスポヌトを芁求し、テンプレヌトから構成ファむルを衚瀺したす。
nginx構成ファむルを最新の状態に保぀こずができたす。
 consul-template -consul <your_consul_ip>:8500 -template server.conf.ctmpl:/etc/nginx/conf.d/server.conf:service nginx reload 


したがっお、Consulテンプレヌトはサヌビスを監芖し、それらをnginx構成に転送したす。 サヌビスが突然クラッシュした堎合、たたはポヌトが倉曎された堎合、Consulテンプレヌトは構成ファむルを曎新し、nginxをリロヌドしたす。

バランサヌnginx、haproxyにConsulテンプレヌトを䜿甚するず非垞に䟿利です。
しかし、これはこのすばらしいツヌルを䜿甚できるナヌザヌ事䟋の1぀にすぎたせん。

Consul Templateの詳现

緎習する





したがっお、ロヌカルホストに4぀の仮想マシンがあり、Debian 8 Jessieがむンストヌルされおおり、カヌネルバヌゞョンが3.16であり、このテクノロゞヌスタックに慣れお、クラスタヌで䜕らかのWebアプリケヌションを実行しようずする時間ず芁望がありたす。

簡単なワヌドプレスブログを䜜成したしょう。

* ここでは、SwarmノヌドずConsulノヌド間でTLSを蚭定する瞬間を省略したす。

ノヌドの環境を蚭定したす。



各仮想マシン以䞋、ノヌドず呌びたすにリポゞトリを远加したす
 echo "deb http://apt.dockerproject.org/repo debian-jessie main" > /etc/apt/sources.list.d/docker.list 

そしお、環境に必芁なパッケヌゞをむンストヌルしたす。
 apt-get update apt-get install ca-certificates apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D apt-get update apt-get install docker-engine aufs-tools 

プラむマリノヌドでのバむンディングの開始
 docker run --restart=unless-stopped -d -h `hostname` --name consul -v /mnt:/data \ -p `ifconfig eth0 | grep 'inet addr:' | cut -d: -f2 | awk '{ print $1}'`:8300:8300 \ -p `ifconfig eth0 | grep 'inet addr:' | cut -d: -f2 | awk '{ print $1}'`:8301:8301 \ -p `ifconfig eth0 | grep 'inet addr:' | cut -d: -f2 | awk '{ print $1}'`:8301:8301/udp \ -p `ifconfig eth0 | grep 'inet addr:' | cut -d: -f2 | awk '{ print $1}'`:8302:8302 \ -p `ifconfig eth0 | grep 'inet addr:' | cut -d: -f2 | awk '{ print $1}'`:8302:8302/udp \ -p `ifconfig eth0 | grep 'inet addr:' | cut -d: -f2 | awk '{ print $1}'`:8400:8400 \ -p 8500:8500 \ -p 172.17.0.1:53:53/udp \ gliderlabs/consul-server -server -rejoin -advertise `ifconfig eth0 | grep 'inet addr:' | cut -d: -f2 | awk '{ print $1}'` -bootstrap 

--restart = without-stoppedオプションは、 docker -daemonが手動で停止されおいない堎合、docker-daemonが再起動しおもコンテナを実行し続けたす 。

Consulの起動埌、systemdのdocker-daemon起動パラメヌタヌを修正する必芁がありたす
/etc/systemd/system/multi-user.target.wants/docker.serviceファむルで、ExecStart行を次のように倉換する必芁がありたす。
 ExecStart=/usr/bin/docker daemon -H fd:// -H tcp://<your_ip>:2375 --storage-driver=aufs --cluster-store=consul://<your_ip>:8500 --cluster-advertise <your_ip>:2375 

そしお、その埌デヌモンを再起動したす
 systemctl daemon-reload service docker restart 

Consulが皌働しおいるこずを確認したす。
 docker ps 

次に、プラむマリノヌドでswarm-managerを実行したす。
 docker run --restart=unless-stopped -d \ -p 3375:2375 \ swarm manage \ --replication \ --advertise `ifconfig eth0 | grep 'inet addr:' | cut -d: -f2 | awk '{ print $1}'`:3375 \ consul://`ifconfig eth0 | grep 'inet addr:' | cut -d: -f2 | awk '{ print $1}'`:8500/ 

manageコマンドは、ノヌドでSwarmマネヌゞャヌを起動したす。
--replicationオプションは、クラスタヌのプラむマリノヌドずセカンダリノヌド間のレプリケヌションを有効にしたす。
 docker run --restart=unless-stopped -d \ swarm join \ --advertise=`ifconfig eth0 | grep 'inet addr:' | cut -d: -f2 | awk '{ print $1}'`:2375 \ consul://`ifconfig eth0 | grep 'inet addr:' | cut -d: -f2 | awk '{ print $1}'`:8500/ 

joinコマンドは、コンテナ内のアプリケヌションを実行するノヌドをswarmクラスタヌに远加したす。
Consulアドレスを枡すこずにより、サヌビス怜出機胜を远加したす。

そしお、もちろん、登録者
 docker run --restart=unless-stopped -d \ --name=registrator \ --net=host \ --volume=/var/run/docker.sock:/tmp/docker.sock \ gliderlabs/registrator:latest \ consul://`ifconfig eth0 | grep 'inet addr:' | cut -d: -f2 | awk '{ print $1}'`:8500 

次に、残りのノヌドに進みたしょう。

Consulの起動
 docker run --restart=unless-stopped -d -h `hostname` --name consul -v /mnt:/data \ -p `ifconfig eth0 | grep 'inet addr:' | cut -d: -f2 | awk '{ print $1}'`:8300:8300 \ -p `ifconfig eth0 | grep 'inet addr:' | cut -d: -f2 | awk '{ print $1}'`:8301:8301 \ -p `ifconfig eth0 | grep 'inet addr:' | cut -d: -f2 | awk '{ print $1}'`:8301:8301/udp \ -p `ifconfig eth0 | grep 'inet addr:' | cut -d: -f2 | awk '{ print $1}'`:8302:8302 \ -p `ifconfig eth0 | grep 'inet addr:' | cut -d: -f2 | awk '{ print $1}'`:8302:8302/udp \ -p `ifconfig eth0 | grep 'inet addr:' | cut -d: -f2 | awk '{ print $1}'`:8400:8400 \ -p `ifconfig eth0 | grep 'inet addr:' | cut -d: -f2 | awk '{ print $1}'`:8500:8500 \ -p 172.17.0.1:53:53/udp \ gliderlabs/consul-server -server -rejoin -advertise `ifconfig eth0 | grep 'inet addr:' | cut -d: -f2 | awk '{ print $1}'` -join <primary_node_ip> 

ここで、 -joinパラメヌタヌでは、䞊蚘で構成したプラむマリノヌドのアドレスを指定する必芁がありたす。

Swarmマネヌゞャヌ
 docker run --restart=unless-stopped -d \ -p 3375:2375 \ swarm manage \ --advertise `ifconfig eth0 | grep 'inet addr:' | cut -d: -f2 | awk '{ print $1}'`:3375 \ consul://`ifconfig eth0 | grep 'inet addr:' | cut -d: -f2 | awk '{ print $1}'`:8500/ 

ノヌドをクラスタヌに接続したす。
 docker run --restart=unless-stopped -d \ swarm join \ --advertise=`ifconfig eth0 | grep 'inet addr:' | cut -d: -f2 | awk '{ print $1}'`:2375 \ consul://`ifconfig eth0 | grep 'inet addr:' | cut -d: -f2 | awk '{ print $1}'`:8500/ 

Consulでサヌビスを登録するための登録者。
 docker run --restart=unless-stopped -d \ --name=registrator \ --net=host \ --volume=/var/run/docker.sock:/tmp/docker.sock \ gliderlabs/registrator:latest \ -ip `ifconfig eth0 | grep 'inet addr:' | cut -d: -f2 | awk '{ print $1}'` \ consul://`ifconfig eth0 | grep 'inet addr:' | cut -d: -f2 | awk '{ print $1}'`:8500 


「クむックコマンド」に぀いお少し


すべおのコンテナを再起動したす
 docker stop $(docker ps -aq);docker start $(docker ps -aq) 

すべおのコンテナを削陀
 docker stop $(docker ps -aq);docker rm $(docker ps -aq) 

非アクティブなコンテナをすべお削陀する
 docker stop $(docker ps -a | grep 'Exited' | awk '{print $1}') && docker rm $(docker ps -a | grep 'Exited' | awk '{print $1}') 

すべおのボリュヌムを削陀するビゞヌ期限切れにならない
 docker volume rm $(docker volume ls -q); 

すべおの画像の削陀ビゞヌ期限切れなし
 docker rmi $(docker images -q); 


フロント゚ンド



したがっお、クラスタヌは䜜業ず防埡の準備ができおいたす。 プラむマリノヌドに戻っお、フロント゚ンドバランサヌを実行したしょう。
䞊で述べたように、コマンドラむンで䜜業するずき、倉数を指定するず䟿利です
 export DOCKER_HOST=tcp://<my_swarm_ip>:3375 

そしお、通垞どおりdockerコマンドを䜿甚したすが、すでにロヌカルノヌドではなく、クラスタヌ党䜓で機胜しおいたす。

phusion-baseimageむメヌゞを䜿甚し、プロセスで少し倉曎したす。 Consulテンプレヌトを远加しお、nginx構成ファむルを最新の状態に保ち、その䞭に皌働䞭および䜜業䞭のワヌカヌのリストを保持する必芁がありたす。 nginx-lbフォルダヌを䜜成し、その䞭に次の内容のDockerfileを䜜成したす。

非衚瀺のテキスト
 FROM phusion/baseimage:0.9.18 ENV NGINX_VERSION 1.8.1-1~trusty ENV DEBIAN_FRONTEND=noninteractive # Avoid ERROR: invoke-rc.d: policy-rc.d denied execution of start. RUN echo "#!/bin/sh\nexit 0" > /usr/sbin/policy-rc.d RUN curl -sS http://nginx.org/keys/nginx_signing.key | sudo apt-key add - && \ echo 'deb http://nginx.org/packages/ubuntu/ trusty nginx' >> /etc/apt/sources.list && \ echo 'deb-src http://nginx.org/packages/ubuntu/ trusty nginx' >> /etc/apt/sources.list && \ apt-get update -qq && apt-get install -y unzip ca-certificates nginx=${NGINX_VERSION} && \ rm -rf /var/lib/apt/lists/* && \ ln -sf /dev/stdout /var/log/nginx/access.log && \ ln -sf /dev/stderr /var/log/nginx/error.log EXPOSE 80 #      Consul Template ADD https://releases.hashicorp.com/consul-template/0.12.2/consul-template_0.12.2_linux_amd64.zip /usr/bin/ RUN unzip /usr/bin/consul-template_0.12.2_linux_amd64.zip -d /usr/local/bin ADD nginx.service /etc/service/nginx/run RUN chmod a+x /etc/service/nginx/run ADD consul-template.service /etc/service/consul-template/run RUN chmod a+x /etc/service/consul-template/run RUN rm -v /etc/nginx/conf.d/*.conf ADD app.conf.ctmpl /etc/consul-templates/app.conf.ctmpl CMD ["/sbin/my_init"] 



次に、nignx起動スクリプトを䜜成する必芁がありたす。 nginx.serviceファむルを䜜成したす。
 #!/bin/sh /usr/sbin/nginx -c /etc/nginx/nginx.conf -t && \ exec /usr/sbin/nginx -c /etc/nginx/nginx.conf -g "daemon off;" 

Consul Template起動スクリプト
 #!/bin/sh exec /usr/local/bin/consul-template \ -consul consul:8500 \ -template "/etc/consul-templates/app.conf.ctmpl:/etc/nginx/conf.d/app.conf:sv hup nginx || true" 

玠晎らしい。 次に、Consulテンプレヌト甚のnginx構成ファむルテンプレヌトが必芁です。 app.confを䜜成したす。

非衚瀺のテキスト
 upstream fpm { least_conn; {{range service "fpm"}}server {{.Address}}:{{.Port}} max_fails=3 fail_timeout=60 weight=1; {{else}}server 127.0.0.1:65535{{end}} } server { listen 80; root /var/www/html; index index.php index.html index.htm; server_name domain.example.com; sendfile off; location / { try_files $uri $uri/ /index.php?q=$uri&$args; } location /doc/ { alias /usr/share/doc/; autoindex on; allow 127.0.0.1; allow ::1; deny all; } error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/www; } location ~ \.php$ { try_files $uri =404; fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name; fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_pass fpm; fastcgi_index index.php; include fastcgi_params; } location ~ /\.ht { deny all; } } 



次に、倉曎されたむメヌゞを䜜成する必芁がありたす。
 docker build -t nginx-lb . 

クラスタヌの各ノヌドでこの画像を手動で収集するか、無料のDocker Hubクラりドにアップロヌドしお、い぀でもどこからでも䞍芁なゞェスチャヌなしで撮圱できる2぀のオプションがありたす。 たたは、個人のDockerレゞストリ内。
Docker Hubの操䜜に぀いおは、 ドキュメントで 詳しく説明しおい たす 。

今が䜕が起こったのかを芋る時です。 コンテナを起動したす。
 docker run -p 80:80 -v /mnt/storage/www:/var/www/html -d --name balancer --link consul:consul -l "SERVICE_NAME=balancer" -l "SERVICE_TAGS=balancer" \ -l "SERVICE_CHECK_HTTP=/" -l "SERVICE_CHECK_INTERVAL=15s" -l "SERVICE_CHECK_TIMEOUT=1s" nginx-lb 

ブラりザを぀぀いお確認しおください。 はい、圌は悪いゲヌトりェむを䞎えるでしょう、なぜなら スタティックもバック゚ンドもありたせん。

バック゚ンド



さお、フロント゚ンドを芋぀けたした。 誰かがPHPコヌドを凊理する必芁がありたす。 これは、FPMを䜿甚したWordPressのむメヌゞに圹立ちたす
ここでも、画像をわずかに修正する必芁がありたす。 ぀たり、Consulテンプレヌトを远加しお、MySQLサヌバヌを怜出したす。 しかし、デヌタベヌスサヌバヌが実行されおいるノヌドを毎回調べお、むメヌゞの起動時にそのアドレスを手動で指定する必芁はありたせんか これにはそれほど時間はかかりたせんが、私たちは怠け者であり、「怠lazは進歩の゚ンゞン」ですc。

Dockerfile
 FROM php:5.6-fpm # install the PHP extensions we need RUN apt-get update && apt-get install -y unzip libpng12-dev libjpeg-dev && rm -rf /var/lib/apt/lists/* \ && docker-php-ext-configure gd --with-png-dir=/usr --with-jpeg-dir=/usr \ && docker-php-ext-install gd mysqli opcache # set recommended PHP.ini settings # see https://secure.php.net/manual/en/opcache.installation.php RUN { \ echo 'opcache.memory_consumption=128'; \ echo 'opcache.interned_strings_buffer=8'; \ echo 'opcache.max_accelerated_files=4000'; \ echo 'opcache.revalidate_freq=60'; \ echo 'opcache.fast_shutdown=1'; \ echo 'opcache.enable_cli=1'; \ } > /usr/local/etc/php/conf.d/opcache-recommended.ini VOLUME /var/www/html ENV WORDPRESS_VERSION 4.4.2 ENV WORDPRESS_SHA1 7444099fec298b599eb026e83227462bcdf312a6 # upstream tarballs include ./wordpress/ so this gives us /usr/src/wordpress RUN curl -o wordpress.tar.gz -SL https://wordpress.org/wordpress-${WORDPRESS_VERSION}.tar.gz \ && echo "$WORDPRESS_SHA1 *wordpress.tar.gz" | sha1sum -c - \ && tar -xzf wordpress.tar.gz -C /usr/src/ \ && rm wordpress.tar.gz \ && chown -R www-data:www-data /usr/src/wordpress ADD https://releases.hashicorp.com/consul-template/0.12.2/consul-template_0.12.2_linux_amd64.zip /usr/bin/ RUN unzip /usr/bin/consul-template_0.12.2_linux_amd64.zip -d /usr/local/bin #    . ADD db.conf.php.ctmpl /db.conf.php.ctmpl #    consul-template ADD consul-template.sh /usr/local/bin/consul-template.sh #    MySQL      WP ADD mysql.ctmpl /tmp/mysql.ctmpl COPY docker-entrypoint.sh /entrypoint.sh # grr, ENTRYPOINT resets CMD now ENTRYPOINT ["/entrypoint.sh"] CMD ["php-fpm"] 



MySQL蚭定テンプレヌトdb.conf.php.ctmplを䜜成したす。
 <?php {{range service "mysql"}} define('DB_HOST', '{{.Address}}'); {{else}} define('DB_HOST', 'mysql'); {{end}} ?> 

そしお、consul-template.sh起動スクリプト
 #!/bin/sh echo "Starting Consul Template" exec /usr/local/bin/consul-template \ -consul consul:8500 \ -template "/db.conf.php.ctmpl:/var/www/html/db.conf.php" 


MySQLサヌバヌ怜出テンプレヌトmysql.ctmpl
 {{range service "mysql"}}{{.Address}} {{.Port}} {{end}} 

docker-entrypoint.shスクリプトでは、いく぀かの修正が必芁です。 ぀たり、Consulテンプレヌトを接続しおMySQLサヌバヌを怜出し、デフォルトで127.0.0.1のみをリッスンするため、fpmを0.0.0.0に切り替えたす。

非衚瀺のテキスト
 #!/bin/bash set -e #    WORDPRESS_DB_HOST="$(/usr/local/bin/consul-template --template=/tmp/mysql-master.ctmpl --consul=consul:8500 --dry -once | awk '{print $1}' | tail -1)" #    WORDPRESS_DB_PORT="$(/usr/local/bin/consul-template --template=/tmp/mysql-master.ctmpl --consul=consul:8500 --dry -once | awk '{print $2}' | tail -1)" if [[ "$1" == apache2* ]] || [ "$1" == php-fpm ]; then if [ -n "$MYSQL_PORT_3306_TCP" ]; then if [ -z "$WORDPRESS_DB_HOST" ]; then WORDPRESS_DB_HOST='mysql' else echo >&2 'warning: both WORDPRESS_DB_HOST and MYSQL_PORT_3306_TCP found' echo >&2 " Connecting to WORDPRESS_DB_HOST ($WORDPRESS_DB_HOST)" echo >&2 ' instead of the linked mysql container' fi fi if [ -z "$WORDPRESS_DB_HOST" ]; then echo >&2 'error: missing WORDPRESS_DB_HOST and MYSQL_PORT_3306_TCP environment variables' echo >&2 ' Did you forget to --link some_mysql_container:mysql or set an external db' echo >&2 ' with -e WORDPRESS_DB_HOST=hostname:port?' exit 1 fi # if we're linked to MySQL and thus have credentials already, let's use them : ${WORDPRESS_DB_USER:=${MYSQL_ENV_MYSQL_USER:-root}} if [ "$WORDPRESS_DB_USER" = 'root' ]; then : ${WORDPRESS_DB_PASSWORD:=$MYSQL_ENV_MYSQL_ROOT_PASSWORD} fi : ${WORDPRESS_DB_PASSWORD:=$MYSQL_ENV_MYSQL_PASSWORD} : ${WORDPRESS_DB_NAME:=${MYSQL_ENV_MYSQL_DATABASE:-wordpress}} if [ -z "$WORDPRESS_DB_PASSWORD" ]; then echo >&2 'error: missing required WORDPRESS_DB_PASSWORD environment variable' echo >&2 ' Did you forget to -e WORDPRESS_DB_PASSWORD=... ?' echo >&2 echo >&2 ' (Also of interest might be WORDPRESS_DB_USER and WORDPRESS_DB_NAME.)' exit 1 fi if ! [ -e index.php -a -e wp-includes/version.php ]; then echo >&2 "WordPress not found in $(pwd) - copying now..." if [ "$(ls -A)" ]; then echo >&2 "WARNING: $(pwd) is not empty - press Ctrl+C now if this is an error!" ( set -x; ls -A; sleep 10 ) fi tar cf - --one-file-system -C /usr/src/wordpress . | tar xf - echo >&2 "Complete! WordPress has been successfully copied to $(pwd)" if [ ! -e .htaccess ]; then # NOTE: The "Indexes" option is disabled in the php:apache base image cat > .htaccess <<-'EOF' # BEGIN WordPress <IfModule mod_rewrite.c> RewriteEngine On RewriteBase / RewriteRule ^index\.php$ - [L] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule . /index.php [L] </IfModule> # END WordPress EOF chown www-data:www-data .htaccess fi fi # TODO handle WordPress upgrades magically in the same way, but only if wp-includes/version.php's $wp_version is less than /usr/src/wordpress/wp-includes/version.php's $wp_version # version 4.4.1 decided to switch to windows line endings, that breaks our seds and awks # https://github.com/docker-library/wordpress/issues/116 # https://github.com/WordPress/WordPress/commit/1acedc542fba2482bab88ec70d4bea4b997a92e4 sed -ri 's/\r\n|\r/\n/g' wp-config* # FPM   0.0.0.0 sed -i 's/listen = 127.0.0.1:9000/listen = 0.0.0.0:9000/g' /usr/local/etc/php-fpm.d/www.conf if [ ! -e wp-config.php ]; then awk '/^\/\*.*stop editing.*\*\/$/ && c == 0 { c = 1; system("cat") } { print }' wp-config-sample.php > wp-config.php <<'EOPHP' // If we're behind a proxy server and using HTTPS, we need to alert Wordpress of that fact // see also http://codex.wordpress.org/Administration_Over_SSL#Using_a_Reverse_Proxy if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') { $_SERVER['HTTPS'] = 'on'; } EOPHP #   Consul Template    MySQL DB_HOST_PRE=$(grep 'DB_HOST' wp-config.php) sed -i "s/$DB_HOST_PRE/include 'db.conf.php';/g" wp-config.php chown www-data:www-data wp-config.php fi # see http://stackoverflow.com/a/2705678/433558 sed_escape_lhs() { echo "$@" | sed 's/[]\/$*.^|[]/\\&/g' } sed_escape_rhs() { echo "$@" | sed 's/[\/&]/\\&/g' } php_escape() { php -r 'var_export(('$2') $argv[1]);' "$1" } set_config() { key="$1" value="$2" var_type="${3:-string}" start="(['\"])$(sed_escape_lhs "$key")\2\s*," end="\);" if [ "${key:0:1}" = '$' ]; then start="^(\s*)$(sed_escape_lhs "$key")\s*=" end=";" fi sed -ri "s/($start\s*).*($end)$/\1$(sed_escape_rhs "$(php_escape "$value" "$var_type")")\3/" wp-config.php } set_config 'DB_HOST' "$WORDPRESS_DB_HOST" set_config 'DB_USER' "$WORDPRESS_DB_USER" set_config 'DB_PASSWORD' "$WORDPRESS_DB_PASSWORD" set_config 'DB_NAME' "$WORDPRESS_DB_NAME" # allow any of these "Authentication Unique Keys and Salts." to be specified via # environment variables with a "WORDPRESS_" prefix (ie, "WORDPRESS_AUTH_KEY") UNIQUES=( AUTH_KEY SECURE_AUTH_KEY LOGGED_IN_KEY NONCE_KEY AUTH_SALT SECURE_AUTH_SALT LOGGED_IN_SALT NONCE_SALT ) for unique in "${UNIQUES[@]}"; do eval unique_value=\$WORDPRESS_$unique if [ "$unique_value" ]; then set_config "$unique" "$unique_value" else # if not specified, let's generate a random value current_set="$(sed -rn "s/define\((([\'\"])$unique\2\s*,\s*)(['\"])(.*)\3\);/\4/p" wp-config.php)" if [ "$current_set" = 'put your unique phrase here' ]; then set_config "$unique" "$(head -c1M /dev/urandom | sha1sum | cut -d' ' -f1)" fi fi done if [ "$WORDPRESS_TABLE_PREFIX" ]; then set_config '$table_prefix' "$WORDPRESS_TABLE_PREFIX" fi if [ "$WORDPRESS_DEBUG" ]; then set_config 'WP_DEBUG' 1 boolean fi TERM=dumb php -- "$WORDPRESS_DB_HOST" "$WORDPRESS_DB_USER" "$WORDPRESS_DB_PASSWORD" "$WORDPRESS_DB_NAME" <<'EOPHP' <?php // database might not exist, so let's try creating it (just to be safe) $stderr = fopen('php://stderr', 'w'); list($host, $port) = explode(':', $argv[1], 2); $maxTries = 10; do { $mysql = new mysqli($host, $argv[2], $argv[3], '', (int)$port); if ($mysql->connect_error) { fwrite($stderr, "\n" . 'MySQL Connection Error: (' . $mysql->connect_errno . ') ' . $mysql->connect_error . "\n"); --$maxTries; if ($maxTries <= 0) { exit(1); } sleep(3); } } while ($mysql->connect_error); if (!$mysql->query('CREATE DATABASE IF NOT EXISTS `' . $mysql->real_escape_string($argv[4]) . '`')) { fwrite($stderr, "\n" . 'MySQL "CREATE DATABASE" Error: ' . $mysql->error . "\n"); $mysql->close(); exit(1); } $mysql->close(); EOPHP fi #  consul-template exec /usr/local/sbin/php-fpm & exec /usr/local/bin/consul-template.sh exec "$@" 



さお、画像を組み立おたしょう
 docker build -t fpm . 

Wordpressの党機胜を実行するデヌタベヌスサヌバヌがないため、ただ起動する必芁はありたせん。
 docker run --name fpm.0 -d -v /mnt/storage/www:/var/www/html \ -e WORDPRESS_DB_NAME=wordpressp -e WORDPRESS_DB_USER=wordpress -e WORDPRESS_DB_PASSWORD=wordpress \ --link consul:consul -l "SERVICE_NAME=php-fpm" -l "SERVICE_PORT=9000" -p 9000:9000 fpm 


デヌタベヌス



マスタヌ



MySQL 5.7むメヌゞをデヌタベヌスずしお䜿甚したす 。

たた、少し修正する必芁がありたす。 すなわち2぀の画像を䜜成したす。 1぀はマスタヌ甚、2぀目はスレヌブ甚です。
Master.

Dockerfile
 FROM debian:jessie # add our user and group first to make sure their IDs get assigned consistently, regardless of whatever dependencies get added RUN groupadd -r mysql && useradd -r -g mysql mysql RUN mkdir /docker-entrypoint-initdb.d # FATAL ERROR: please install the following Perl modules before executing /usr/local/mysql/scripts/mysql_install_db: # File::Basename # File::Copy # Sys::Hostname # Data::Dumper RUN apt-get update && apt-get install -y perl pwgen --no-install-recommends && rm -rf /var/lib/apt/lists/* # gpg: key 5072E1F5: public key "MySQL Release Engineering <mysql-build@oss.oracle.com>" imported RUN apt-key adv --keyserver ha.pool.sks-keyservers.net --recv-keys A4A9406876FCBD3C456770C88C718D3B5072E1F5 ENV MYSQL_MAJOR 5.7 ENV MYSQL_VERSION 5.7.11-1debian8 RUN echo "deb http://repo.mysql.com/apt/debian/ jessie mysql-${MYSQL_MAJOR}" > /etc/apt/sources.list.d/mysql.list # the "/var/lib/mysql" stuff here is because the mysql-server postinst doesn't have an explicit way to disable the mysql_install_db codepath besides having a database already "configured" (ie, stuff in /var/lib/mysql/mysql) # also, we set debconf keys to make APT a little quieter RUN { \ echo mysql-community-server mysql-community-server/data-dir select ''; \ echo mysql-community-server mysql-community-server/root-pass password ''; \ echo mysql-community-server mysql-community-server/re-root-pass password ''; \ echo mysql-community-server mysql-community-server/remove-test-db select false; \ } | debconf-set-selections \ && apt-get update && apt-get install -y mysql-server="${MYSQL_VERSION}" && rm -rf /var/lib/apt/lists/* \ && rm -rf /var/lib/mysql && mkdir -p /var/lib/mysql # comment out a few problematic configuration values # don't reverse lookup hostnames, they are usually another container RUN sed -Ei 's/^(bind-address|log)/#&/' /etc/mysql/my.cnf \ && echo 'skip-host-cache\nskip-name-resolve' | awk '{ print } $1 == "[mysqld]" && c == 0 { c = 1; system("cat") }' /etc/mysql/my.cnf > /tmp/my.cnf \ && mv /tmp/my.cnf /etc/mysql/my.cnf VOLUME /var/lib/mysql COPY docker-entrypoint.sh /entrypoint.sh ENTRYPOINT ["/entrypoint.sh"] EXPOSE 3306 CMD ["mysqld"] 



MySQL:

docker-entrypoint.sh
 #!/bin/bash set -eo pipefail # if command starts with an option, prepend mysqld if [ "${1:0:1}" = '-' ]; then set -- mysqld "$@" fi if [ "$1" = 'mysqld' ]; then # Get config DATADIR="$("$@" --verbose --help 2>/dev/null | awk '$1 == "datadir" { print $2; exit }')" if [ ! -d "$DATADIR/mysql" ]; then if [ -z "$MYSQL_ROOT_PASSWORD" -a -z "$MYSQL_ALLOW_EMPTY_PASSWORD" -a -z "$MYSQL_RANDOM_ROOT_PASSWORD" ]; then echo >&2 'error: database is uninitialized and password option is not specified ' echo >&2 ' You need to specify one of MYSQL_ROOT_PASSWORD, MYSQL_ALLOW_EMPTY_PASSWORD and MYSQL_RANDOM_ROOT_PASSWORD' exit 1 fi mkdir -p "$DATADIR" chown -R mysql:mysql "$DATADIR" echo 'Initializing database' "$@" --initialize-insecure echo 'Database initialized' "$@" --skip-networking & pid="$!" mysql=( mysql --protocol=socket -uroot ) for i in {30..0}; do if echo 'SELECT 1' | "${mysql[@]}" &> /dev/null; then break fi echo 'MySQL init process in progress...' sleep 1 done if [ "$i" = 0 ]; then echo >&2 'MySQL init process failed.' exit 1 fi if [ -n "${REPLICATION_MASTER}" ]; then echo "=> Configuring MySQL replication as master (1/2) ..." if [ ! -f /replication_set.1 ]; then echo "=> Writting configuration file /etc/mysql/my.cnf with server-id=1" echo 'server-id = 1' >> /etc/mysql/my.cnf echo 'log-bin = mysql-bin' >> /etc/mysql/my.cnf touch /replication_set.1 else echo "=> MySQL replication master already configured, skip" fi fi # Set MySQL REPLICATION - SLAVE if [ -n "${REPLICATION_SLAVE}" ]; then echo "=> Configuring MySQL replication as slave (1/2) ..." if [ -n "${MYSQL_PORT_3306_TCP_ADDR}" ] && [ -n "${MYSQL_PORT_3306_TCP_PORT}" ]; then if [ ! -f /replication_set.1 ]; then echo "=> Writting configuration file /etc/mysql/my.cnf with server-id=2" echo 'server-id = 2' >> /etc/mysql/my.cnf echo 'log-bin = mysql-bin' >> /etc/mysql/my.cnf echo 'log-bin=slave-bin' >> /etc/mysql/my.cnf touch /replication_set.1 else echo "=> MySQL replication slave already configured, skip" fi else echo "=> Cannot configure slave, please link it to another MySQL container with alias as 'mysql'" exit 1 fi fi # Set MySQL REPLICATION - SLAVE if [ -n "${REPLICATION_SLAVE}" ]; then echo "=> Configuring MySQL replication as slave (2/2) ..." if [ -n "${MYSQL_PORT_3306_TCP_ADDR}" ] && [ -n "${MYSQL_PORT_3306_TCP_PORT}" ]; then if [ ! -f /replication_set.2 ]; then echo "=> Setting master connection info on slave" echo "!!! DEBUG: ${REPLICATION_USER}, ${REPLICATION_PASS}." "${mysql[@]}" <<-EOSQL -- What's done in this file shouldn't be replicated -- or products like mysql-fabric won't work SET @@SESSION.SQL_LOG_BIN=0; CHANGE MASTER TO MASTER_HOST='${MYSQL_PORT_3306_TCP_ADDR}',MASTER_USER='${REPLICATION_USER}',MASTER_PASSWORD='${REPLICATION_PASS}',MASTER_PORT=${MYSQL_PORT_3306_TCP_PORT}, MASTER_CONNECT_RETRY=30; START SLAVE ; EOSQL echo "=> Done!" touch /replication_set.2 else echo "=> MySQL replication slave already configured, skip" fi else echo "=> Cannot configure slave, please link it to another MySQL container with alias as 'mysql'" exit 1 fi fi if [ -z "$MYSQL_INITDB_SKIP_TZINFO" ]; then # sed is for https://bugs.mysql.com/bug.php?id=20545 mysql_tzinfo_to_sql /usr/share/zoneinfo | sed 's/Local time zone must be set--see zic manual page/FCTY/' | "${mysql[@]}" mysql fi if [ ! -z "$MYSQL_RANDOM_ROOT_PASSWORD" ]; then MYSQL_ROOT_PASSWORD="$(pwgen -1 32)" echo "GENERATED ROOT PASSWORD: $MYSQL_ROOT_PASSWORD" fi "${mysql[@]}" <<-EOSQL -- What's done in this file shouldn't be replicated -- or products like mysql-fabric won't work SET @@SESSION.SQL_LOG_BIN=0; DELETE FROM mysql.user ; CREATE USER 'root'@'%' IDENTIFIED BY '${MYSQL_ROOT_PASSWORD}' ; GRANT ALL ON *.* TO 'root'@'%' WITH GRANT OPTION ; DROP DATABASE IF EXISTS test ; FLUSH PRIVILEGES ; EOSQL if [ ! -z "$MYSQL_ROOT_PASSWORD" ]; then mysql+=( -p"${MYSQL_ROOT_PASSWORD}" ) fi # Set MySQL REPLICATION - MASTER if [ -n "${REPLICATION_MASTER}" ]; then echo "=> Configuring MySQL replication as master (2/2) ..." if [ ! -f /replication_set.2 ]; then echo "=> Creating a log user ${REPLICATION_USER}:${REPLICATION_PASS}" "${mysql[@]}" <<-EOSQL -- What's done in this file shouldn't be replicated -- or products like mysql-fabric won't work SET @@SESSION.SQL_LOG_BIN=0; CREATE USER '${REPLICATION_USER}'@'%' IDENTIFIED BY '${REPLICATION_PASS}'; GRANT REPLICATION SLAVE ON *.* TO '${REPLICATION_USER}'@'%' ; FLUSH PRIVILEGES ; RESET MASTER ; EOSQL echo "=> Done!" touch /replication_set.2 else echo "=> MySQL replication master already configured, skip" fi fi if [ "$MYSQL_DATABASE" ]; then echo "CREATE DATABASE IF NOT EXISTS \`$MYSQL_DATABASE\` ;" | "${mysql[@]}" mysql+=( "$MYSQL_DATABASE" ) fi if [ "$MYSQL_USER" -a "$MYSQL_PASSWORD" ]; then echo "CREATE USER '$MYSQL_USER'@'%' IDENTIFIED BY '$MYSQL_PASSWORD' ;" | "${mysql[@]}" if [ "$MYSQL_DATABASE" ]; then echo "GRANT ALL ON \`$MYSQL_DATABASE\`.* TO '$MYSQL_USER'@'%' ;" | "${mysql[@]}" fi echo 'FLUSH PRIVILEGES ;' | "${mysql[@]}" fi echo for f in /docker-entrypoint-initdb.d/*; do case "$f" in *.sh) echo "$0: running $f"; . "$f" ;; *.sql) echo "$0: running $f"; "${mysql[@]}" < "$f"; echo ;; *.sql.gz) echo "$0: running $f"; gunzip -c "$f" | "${mysql[@]}"; echo ;; *) echo "$0: ignoring $f" ;; esac echo done if [ ! -z "$MYSQL_ONETIME_PASSWORD" ]; then "${mysql[@]}" <<-EOSQL ALTER USER 'root'@'%' PASSWORD EXPIRE; EOSQL fi if ! kill -s TERM "$pid" || ! wait "$pid"; then echo >&2 'MySQL init process failed.' exit 1 fi echo echo 'MySQL init process done. Ready for start up.' echo fi chown -R mysql:mysql "$DATADIR" fi exec "$@" 



:
 docker build -t mysql-master . 

 docker run --name mysql-master.0 -v /mnt/volumes/master:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=rootpass -e MYSQL_USER=wordpress -e MYSQL_PASSWORD=wordpress -e MYSQL_DB=wordpress -e REPLICATION_MASTER=true -e REPLICATION_USER=replica -e REPLICATION_PASS=replica --link consul:consul -l "SERVICE_NAME=master" -l "SERVICE_PORT=3306" -p 3306:3306 -d mysql-master 


, MySQL (REPLICATION_USER, REPLICATION_PASS, REPLICATION_MASTER, REPLICATION_SLAVE).

Slave



Slave , MySQL Master- . Consul Template:

Dockerfile
 FROM debian:jessie # add our user and group first to make sure their IDs get assigned consistently, regardless of whatever dependencies get added RUN groupadd -r mysql && useradd -r -g mysql mysql RUN mkdir /docker-entrypoint-initdb.d # FATAL ERROR: please install the following Perl modules before executing /usr/local/mysql/scripts/mysql_install_db: # File::Basename # File::Copy # Sys::Hostname # Data::Dumper RUN apt-get update && apt-get install -y perl pwgen --no-install-recommends && rm -rf /var/lib/apt/lists/* # gpg: key 5072E1F5: public key "MySQL Release Engineering <mysql-build@oss.oracle.com>" imported RUN apt-key adv --keyserver ha.pool.sks-keyservers.net --recv-keys A4A9406876FCBD3C456770C88C718D3B5072E1F5 ENV MYSQL_MAJOR 5.7 ENV MYSQL_VERSION 5.7.11-1debian8 RUN echo "deb http://repo.mysql.com/apt/debian/ jessie mysql-${MYSQL_MAJOR}" > /etc/apt/sources.list.d/mysql.list # the "/var/lib/mysql" stuff here is because the mysql-server postinst doesn't have an explicit way to disable the mysql_install_db codepath besides having a database already "configured" (ie, stuff in /var/lib/mysql/mysql) # also, we set debconf keys to make APT a little quieter RUN { \ echo mysql-community-server mysql-community-server/data-dir select ''; \ echo mysql-community-server mysql-community-server/root-pass password ''; \ echo mysql-community-server mysql-community-server/re-root-pass password ''; \ echo mysql-community-server mysql-community-server/remove-test-db select false; \ } | debconf-set-selections \ && apt-get update && apt-get install -y mysql-server="${MYSQL_VERSION}" && rm -rf /var/lib/apt/lists/* \ && rm -rf /var/lib/mysql && mkdir -p /var/lib/mysql # comment out a few problematic configuration values # don't reverse lookup hostnames, they are usually another container RUN sed -Ei 's/^(bind-address|log)/#&/' /etc/mysql/my.cnf \ && echo 'skip-host-cache\nskip-name-resolve' | awk '{ print } $1 == "[mysqld]" && c == 0 { c = 1; system("cat") }' /etc/mysql/my.cnf > /tmp/my.cnf \ && mv /tmp/my.cnf /etc/mysql/my.cnf ADD https://releases.hashicorp.com/consul-template/0.12.2/consul-template_0.12.2_linux_amd64.zip /usr/bin/ RUN unzip /usr/bin/consul-template_0.12.2_linux_amd64.zip -d /usr/local/bin ADD mysql-master.ctmpl /tmp/mysql-master.ctmpl VOLUME /var/lib/mysql COPY docker-entrypoint.sh /entrypoint.sh ENTRYPOINT ["/entrypoint.sh"] EXPOSE 3306 CMD ["mysqld"] 



docker-entrypoint.sh
 #!/bin/bash set -eo pipefail #   Consul,     master MYSQL_PORT_3306_TCP_ADDR="$(/usr/bin/consul-template --template=/tmp/mysql-master.ctmpl --consul=consul:8500 --dry -once | awk '{print $1}' | tail -1)" MYSQL_PORT_3306_TCP_PORT="$(/usr/bin/consul-template --template=/tmp/mysql-master.ctmpl --consul=consul:8500 --dry -once | awk '{print $2}' | tail -1)" if [ "${1:0:1}" = '-' ]; then set -- mysqld "$@" fi if [ "$1" = 'mysqld' ]; then # Get config DATADIR="$("$@" --verbose --help 2>/dev/null | awk '$1 == "datadir" { print $2; exit }')" if [ ! -d "$DATADIR/mysql" ]; then if [ -z "$MYSQL_ROOT_PASSWORD" -a -z "$MYSQL_ALLOW_EMPTY_PASSWORD" -a -z "$MYSQL_RANDOM_ROOT_PASSWORD" ]; then echo >&2 'error: database is uninitialized and password option is not specified ' echo >&2 ' You need to specify one of MYSQL_ROOT_PASSWORD, MYSQL_ALLOW_EMPTY_PASSWORD and MYSQL_RANDOM_ROOT_PASSWORD' exit 1 fi mkdir -p "$DATADIR" chown -R mysql:mysql "$DATADIR" echo 'Initializing database' "$@" --initialize-insecure echo 'Database initialized' "$@" --skip-networking & pid="$!" mysql=( mysql --protocol=socket -uroot ) for i in {30..0}; do if echo 'SELECT 1' | "${mysql[@]}" &> /dev/null; then break fi echo 'MySQL init process in progress...' sleep 1 done if [ "$i" = 0 ]; then echo >&2 'MySQL init process failed.' exit 1 fi if [ -n "${REPLICATION_MASTER}" ]; then echo "=> Configuring MySQL replication as master (1/2) ..." if [ ! -f /replication_set.1 ]; then echo "=> Writting configuration file /etc/mysql/my.cnf with server-id=1" echo 'server-id = 1' >> /etc/mysql/my.cnf echo 'log-bin = mysql-bin' >> /etc/mysql/my.cnf touch /replication_set.1 else echo "=> MySQL replication master already configured, skip" fi fi # Set MySQL REPLICATION - SLAVE if [ -n "${REPLICATION_SLAVE}" ]; then echo "=> Configuring MySQL replication as slave (1/2) ..." if [ -n "${MYSQL_PORT_3306_TCP_ADDR}" ] && [ -n "${MYSQL_PORT_3306_TCP_PORT}" ]; then if [ ! -f /replication_set.1 ]; then echo "=> Writting configuration file /etc/mysql/my.cnf with server-id=2" echo 'server-id = 2' >> /etc/mysql/my.cnf echo 'log-bin = mysql-bin' >> /etc/mysql/my.cnf echo 'log-bin=slave-bin' >> /etc/mysql/my.cnf touch /replication_set.1 else echo "=> MySQL replication slave already configured, skip" fi else echo "=> Cannot configure slave, please link it to another MySQL container with alias as 'mysql'" exit 1 fi fi # Set MySQL REPLICATION - SLAVE if [ -n "${REPLICATION_SLAVE}" ]; then echo "=> Configuring MySQL replication as slave (2/2) ..." if [ -n "${MYSQL_PORT_3306_TCP_ADDR}" ] && [ -n "${MYSQL_PORT_3306_TCP_PORT}" ]; then if [ ! -f /replication_set.2 ]; then echo "=> Setting master connection info on slave" "${mysql[@]}" <<-EOSQL -- What's done in this file shouldn't be replicated -- or products like mysql-fabric won't work SET @@SESSION.SQL_LOG_BIN=0; CHANGE MASTER TO MASTER_HOST='${MYSQL_PORT_3306_TCP_ADDR}',MASTER_USER='${REPLICATION_USER}',MASTER_PASSWORD='${REPLICATION_PASS}',MASTER_PORT=${MYSQL_PORT_3306_TCP_PORT}, MASTER_CONNECT_RETRY=30; START SLAVE ; EOSQL echo "=> Done!" touch /replication_set.2 else echo "=> MySQL replication slave already configured, skip" fi else echo "=> Cannot configure slave, please link it to another MySQL container with alias as 'mysql'" exit 1 fi fi if [ -z "$MYSQL_INITDB_SKIP_TZINFO" ]; then # sed is for https://bugs.mysql.com/bug.php?id=20545 mysql_tzinfo_to_sql /usr/share/zoneinfo | sed 's/Local time zone must be set--see zic manual page/FCTY/' | "${mysql[@]}" mysql fi if [ ! -z "$MYSQL_RANDOM_ROOT_PASSWORD" ]; then MYSQL_ROOT_PASSWORD="$(pwgen -1 32)" echo "GENERATED ROOT PASSWORD: $MYSQL_ROOT_PASSWORD" fi "${mysql[@]}" <<-EOSQL -- What's done in this file shouldn't be replicated -- or products like mysql-fabric won't work SET @@SESSION.SQL_LOG_BIN=0; DELETE FROM mysql.user ; CREATE USER 'root'@'%' IDENTIFIED BY '${MYSQL_ROOT_PASSWORD}' ; GRANT ALL ON *.* TO 'root'@'%' WITH GRANT OPTION ; DROP DATABASE IF EXISTS test ; FLUSH PRIVILEGES ; EOSQL if [ ! -z "$MYSQL_ROOT_PASSWORD" ]; then mysql+=( -p"${MYSQL_ROOT_PASSWORD}" ) fi # Set MySQL REPLICATION - MASTER if [ -n "${REPLICATION_MASTER}" ]; then echo "=> Configuring MySQL replication as master (2/2) ..." if [ ! -f /replication_set.2 ]; then echo "=> Creating a log user ${REPLICATION_USER}:${REPLICATION_PASS}" "${mysql[@]}" <<-EOSQL -- What's done in this file shouldn't be replicated -- or products like mysql-fabric won't work SET @@SESSION.SQL_LOG_BIN=0; CREATE USER '${REPLICATION_USER}'@'%' IDENTIFIED BY '${REPLICATION_PASS}'; GRANT REPLICATION SLAVE ON *.* TO '${REPLICATION_USER}'@'%' ; FLUSH PRIVILEGES ; RESET MASTER ; EOSQL echo "=> Done!" touch /replication_set.2 else echo "=> MySQL replication master already configured, skip" fi fi if [ "$MYSQL_DATABASE" ]; then echo "CREATE DATABASE IF NOT EXISTS \`$MYSQL_DATABASE\` ;" | "${mysql[@]}" mysql+=( "$MYSQL_DATABASE" ) fi if [ "$MYSQL_USER" -a "$MYSQL_PASSWORD" ]; then echo "CREATE USER '$MYSQL_USER'@'%' IDENTIFIED BY '$MYSQL_PASSWORD' ;" | "${mysql[@]}" if [ "$MYSQL_DATABASE" ]; then echo "GRANT ALL ON \`$MYSQL_DATABASE\`.* TO '$MYSQL_USER'@'%' ;" | "${mysql[@]}" fi echo 'FLUSH PRIVILEGES ;' | "${mysql[@]}" fi echo for f in /docker-entrypoint-initdb.d/*; do case "$f" in *.sh) echo "$0: running $f"; . "$f" ;; *.sql) echo "$0: running $f"; "${mysql[@]}" < "$f"; echo ;; *.sql.gz) echo "$0: running $f"; gunzip -c "$f" | "${mysql[@]}"; echo ;; *) echo "$0: ignoring $f" ;; esac echo done if [ ! -z "$MYSQL_ONETIME_PASSWORD" ]; then "${mysql[@]}" <<-EOSQL ALTER USER 'root'@'%' PASSWORD EXPIRE; EOSQL fi if ! kill -s TERM "$pid" || ! wait "$pid"; then echo >&2 'MySQL init process failed.' exit 1 fi echo echo 'MySQL init process done. Ready for start up.' echo fi chown -R mysql:mysql "$DATADIR" fi exec "$@" 



Consul Template, mysql-master.ctmpl:
 {{range service "master"}}{{.Address}} {{.Port}} {{end}} 

収集するもの
 docker build -t mysql-slave . 

以䞋を開始したす。
 docker run --name mysql-slave.0 -v /mnt/volumes/slave:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=rootpass -e REPLICATION_SLAVE=true -e REPLICATION_USER=replica -e REPLICATION_PASS=replica --link=consul:consul -l "SERVICE_NAME=slave" -l "SERVICE_PORT=3307" -p 3307:3306 -d mysql-slave 

, .
 docker run --name fpm.0 -d -v /mnt/storage/www:/var/www/html \ -e WORDPRESS_DB_NAME=wordpressp -e WORDPRESS_DB_USER=wordpress -e WORDPRESS_DB_PASSWORD=wordpress \ --link consul:consul -l "SERVICE_NAME=php-fpm" -l "SERVICE_PORT=9000" -l "SERVICE_TAGS=worker" -p 9000:9000 fpm 

, , , Wordress .
—
 docker logs <container_name> 


Docker-compose.



, , , 
 , , ? — docker-compose .
. Docker-compose YAML, . .

, - docker-compose.yml.

非衚瀺のテキスト
 mysql-master: image: mysql-master ports: - "3306:3306" environment: - "MYSQL_DATABASE=wp" - "MYSQL_USER=wordpress" - "MYSQL_PASSWORD=wordpress" - "REPLICATION_MASTER=true" - "REPLICATION_USER=replica" - "REPLICATION_PASS=replica" external_links: - consul:consul labels: - "SERVICE_NAME=mysql-master" - "SERVICE_PORT=3306" - "SERVICE_TAGS=db" volumes: - '/mnt/storage/master:/var/lib/mysql' mysql-slave: image: mysql-slave ports: - "3307:3306" environment: - "REPLICATION_SLAVE=true" - "REPLICATION_USER=replica" - "REPLICATION_PASS=replica" external_links: - consul:consul labels: - "SERVICE_NAME=mysql-slave" - "SERVICE_PORT=3307" - "SERVICE_TAGS=db" volumes: - '/mnt/storage/slave:/var/lib/mysql' wordpress: image: fpm ports: - "9000:9000" environment: - "WORDPRESS_DB_NAME=wp" - "WORDPRESS_DB_USER=wordpress" - "WORDPRESS_DB_PASSWORD=wordpress" external_links: - consul:consul labels: - "SERVICE_NAME=php-fpm" - "SERVICE_PORT=9000" - "SERVICE_TAGS=worker" volumes: - '/mnt/storage/www:/var/www/html' 



«» , .
 docker-compose up 


おわりに





— .
Swarm . , . « ».

— .
, — . — . .

— .
, .

— .
docker-compose .



.
, Docker stateful-. flocker, , «» .
glusterfs, lsyncd. Glusterfs, , , .

, — .



PS
how-to, .
/ , , .

Source: https://habr.com/ru/post/J278939/


All Articles