Slide 1

Slide 1 text

PHPシステムを コンテナで 動かすための 取り組みのすべて PHPerKaigi 2020 2020/02/11 きくもと (@takakiku)

Slide 2

Slide 2 text

自己紹介 ★ きくもと ★ Twitter: @takakiku ★ 所属: Hamee(ハミィ)株式会社 ○ 小田原にあります! ○ ランチセッションにGo! ★ お仕事: SRE、マネージャー ★ その他 ○ PHPerKaigi 2020 当日スタッフ 2

Slide 3

Slide 3 text

話すこと、話さないこと ★ PHPコンテナを動かす際に実際に 取り組んだことを話します。 ○ 基本泥臭い話しばかりです。 ○ 「正しい」とは限らない。 ★ PHP成分はほんの僅かです。 ★ Dockerそのものや、各種ツールの 細かい説明はしません。 3

Slide 4

Slide 4 text

❖ 背景 ❖ システムの動作まわり ❖ Docker Image ❖ CI/CD ❖ 開発環境 4 Agenda

Slide 5

Slide 5 text

❖ 背景 ❖ システムの動作まわり ❖ Docker Image ❖ CI/CD ❖ 開発環境 5 Agenda

Slide 6

Slide 6 text

こんなシステムがありまして 6 ロードバランサ リバプロ RDBMS Appサーバ Apache mod_php モノリスなPHPコード (コードベースは1つ) Webリクエスト処理 プロセス メール受信処理 プロセス バッチ処理 プロセス

Slide 7

Slide 7 text

AWSへ移行したい 7 ELB ECS Webリクエスト処理 Apache mod_php AWS Batch Lambda SNS SQS SES CloudWatch Events メール受信処理 バッチ処理

Slide 8

Slide 8 text

その前に、、、 ★ コンテナ化しないと ★ 既存環境でコンテナ化された状態で 動作させて、実績を作っておきたい ★ AWSでの移行イメージを持ちやすい 状態にしたい 8

Slide 9

Slide 9 text

❖ 背景 ❖ システムの動作まわり ❖ Docker Image ❖ CI/CD ❖ 開発環境 9 Agenda

Slide 10

Slide 10 text

話すシステムのイメージ 10 10 ロードバランサ リバプロ RDBMS Appサーバ Webリクエスト処理 コンテナ メール受信処理 コンテナ バッチ処理 コンテナ Apache mod_php 共通 Docker Image

Slide 11

Slide 11 text

ログ収集 - コンテナ出力 ★ ログドライバにfluentdを指定 ★ dockerホスト上でfluent-agent-hydra を動かしている ○ https:/ /github.com/fujiwara/fluent-agent-hydra ○ Kayac @fujiwara さん作成 ○ Go 実装(docker ホストにruby不要) 11 docker run \ --log-driver=fluentd \ --log-opt fluentd-address=localhost:24224 \ <略>

Slide 12

Slide 12 text

ログ収集 - その他ログ ★ 各コンテナはdockerホスト上のディレク トリをマウント ○ ログはホスト上に出力される ★ docker ホスト上で fluent-agent-chimeraを動かしている ○ 拙作 -https://kikumoto.hatenablog.com/entry/2018/02/02/095629 ○ fluent-agent-hydraをベース ○ 動的に生成されるログを取り込み fluent-agent-hydraに転送 12

Slide 13

Slide 13 text

システム起動まわり ★ systemdな環境 ★ システム起動時にコンテナ(Webリク エスト処理)を起動したい。 ★ コンテナ起動前に、fluentdがPORTを LISTENしている必要。 13

Slide 14

Slide 14 text

★ Unit ファイル システム起動まわり 14 [Unit] After=fluent-agent-hydra.service docker.service Wants=fluent-agent-hydra.service docker.service [Service] Type=oneshot RemainAfterExit=yes ExecStart=<24224ポートがLISTENされるまで待つスクリプト> ExecStart=<docker run するスクリプト> ExecStop=<Apacheをgraceful shutdownするスクリプト>

Slide 15

Slide 15 text

兄弟コンテナ ★ crondコンテナも存在 ○ 開発環境再現の容易にするため ○ コンテナ内からdocker runする必要 ■ docker コマンドをイメージに仕込済 ■ /var/run/docker.sock をマウント 15 docker run \ --mount \ type=bind,source=/var/run/docker.sock,target=/var/run/docker.sock \ <略>

Slide 16

Slide 16 text

メール送信 ★ コンテナ内からメール送信 ○ ssmtp を利用 ■ sendmail_path = /usr/sbin/ssmtp -t ■ ssmtp.conf 16 mailhub=172.30.1.1:25 FromLineOverride=yes コンテナネットワーク上で のdocker ホストのIPと MTAのポート

Slide 17

Slide 17 text

❖ 背景 ❖ システムの動作まわり ❖ Docker Image ❖ CI/CD ❖ 開発環境 17 Agenda

Slide 18

Slide 18 text

Dockerfile ★ 3つのDockerfile ○ つまり、3つの Docker Image 18 OSおよび言語ランタイムを インストールしたイメージ アプリケーションが依存する外部 ツールやライブラリ アプリケーションコードや 設定 変更の頻度を意識し た構成 通常時は最上位の イメージをビルドす るだけ。

Slide 19

Slide 19 text

Dockerfile 19 # syntax = docker/dockerfile:experimental FROM hamee/hoge_appenv:1.0.1 MAINTAINER Takahiro.Kikumoto WORKDIR /root RUN --mount=type=bind,target=. \ mitamae local ./docker/itamae/recipe.rb && \ rm -rf /var/cache/yum/* && \ yum clean all EXPOSE 80 ENTRYPOINT [\ "render", \ "/path/to/hogeapp/config.ini", \ "/etc/ssmtp/ssmtp.conf", \ "--", \ "/usr/local/bin/start.sh" \ ]

Slide 20

Slide 20 text

Dockerfile 20 # syntax = docker/dockerfile:experimental FROM hamee/hoge_appenv:1.0.1 MAINTAINER Takahiro.Kikumoto WORKDIR /root RUN --mount=type=bind,target=. \ mitamae local ./docker/itamae/recipe.rb && \ rm -rf /var/cache/yum/* && \ yum clean all EXPOSE 80 ENTRYPOINT [\ "render", \ "/path/to/hogeapp/config.ini", \ "/etc/ssmtp/ssmtp.conf", \ "--", \ "/usr/local/bin/start.sh" \ ] mitamae local ./docker/itamae/recipe.rb

Slide 21

Slide 21 text

mitamae ★ itamaeのmruby実装 ○ ワンバイナリ(rubyランタイム不要!) ○ itamae ■ 構成管理ツール ■ Chefの簡易版みたいな感じ ○ 採用理由 ■ もともとChefの資産があった ■ Dockerfileが長大になるのを避けたかった ● 逆に、itamaeを知る必要あるのだけど。 21

Slide 22

Slide 22 text

Dockerfile 22 # syntax = docker/dockerfile:experimental FROM hamee/hoge_appenv:1.0.1 MAINTAINER Takahiro.Kikumoto WORKDIR /root RUN --mount=type=bind,target=. \ mitamae local ./docker/itamae/recipe.rb && \ rm -rf /var/cache/yum/* && \ yum clean all EXPOSE 80 ENTRYPOINT [\ "render", \ "/path/to/hogeapp/config.ini", \ "/etc/ssmtp/ssmtp.conf", \ "--", \ "/usr/local/bin/start.sh" \ ] # syntax = docker/dockerfile:experimental RUN --mount=type=bind,target=.

Slide 23

Slide 23 text

BuildKit ★ BuildKitを利用 ○ export DOCKER_BUILDKIT=1 ○ Dockerfile frontend experimental syntaxes ■ RUN --mount=type=bind ■ Itamaeのレシピをイメージにコピーすることなくコ ンテナにマウントして利用できる。 ● 不要なDockerレイヤー削除 ● COPY不要によるビルド時間短縮 23

Slide 24

Slide 24 text

Dockerfile 24 # syntax = docker/dockerfile:experimental FROM hamee/hoge_appenv:1.0.1 MAINTAINER Takahiro.Kikumoto WORKDIR /root RUN --mount=type=bind,target=. \ mitamae local ./docker/itamae/recipe.rb && \ rm -rf /var/cache/yum/* && \ yum clean all EXPOSE 80 ENTRYPOINT [\ "render", \ "/path/to/hogeapp/config.ini", \ "/etc/ssmtp/ssmtp.conf", \ "--", \ "/usr/local/bin/start.sh" \ ] "render", \ "/path/to/hogeapp/config.ini", \ "/etc/ssmtp/ssmtp.conf",

Slide 25

Slide 25 text

entrykit ★ entrykitを利用 ○ https:/ /github.com/progrium/entrykit ○ 起動時にテンプレートおよび環境変数 からファイル生成したり、事前コマンド の実行とか、引数に応じて実行プロセ スを変えるとか。 ○ 今回は、テンプレートからのファイル生 成用途 25

Slide 26

Slide 26 text

entrykit 26 mailhub={{ var "SMTP_ADDR" | default "localhost" }}:{{ var "SMTP_PORT" | default "25" }} /etc/ssmtp/ssmtp.conf.tmpl Docker run \ --env-file=env.txt SMTP_ADDR=172.30.1.1 SMTP_PORT=25 env.txt mailhub=172.30.1.1:25 /etc/ssmtp/ssmtp.conf

Slide 27

Slide 27 text

Dockerfile 27 # syntax = docker/dockerfile:experimental FROM hamee/hoge_appenv:1.0.1 MAINTAINER Takahiro.Kikumoto WORKDIR /root RUN --mount=type=bind,target=. \ mitamae local ./docker/itamae/recipe.rb && \ rm -rf /var/cache/yum/* && \ yum clean all EXPOSE 80 ENTRYPOINT [\ "render", \ "/path/to/hogeapp/config.ini", \ "/etc/ssmtp/ssmtp.conf", \ "--", \ "/usr/local/bin/start.sh" \ ] /usr/local/bin/start.sh

Slide 28

Slide 28 text

コンテナの動作変更 ★ docker run の引数で動作モードを 制御 ○ entrykit の switch では、引数を渡すこ とができなかった。 28 #!/bin/sh mode=$1 shift case $mode in "php") exec /usr/bin/php "$@" ;; "webapp") exec /usr/sbin/httpd -D FOREGROUND ;; *) exec /bin/bash "$@" ;; esac

Slide 29

Slide 29 text

❖ 背景 ❖ システムの動作まわり ❖ Docker Image ❖ CI/CD ❖ 開発環境 29 Agenda

Slide 30

Slide 30 text

ピタゴラスイッチ 30 Dockerビルド AWS Systems Manager Run Command deploy script Appサーバ push hook push pull api exec 新コンテナ

Slide 31

Slide 31 text

CircleCIでのポイント ★ BuildKit利用、mountも。 ○ docker executor ■ dockerのバージョンは新しい ● BuildKitはサポートしているバージョン ■ mountができない。 ○ machine executor ■ デフォルトイメージでは、dockerのバージョン が古い ■ ubuntu-1604:201903-01 を使用 ● https://circleci.com/docs/ja/2.0/configuration-reference/#machine 31

Slide 32

Slide 32 text

AWS Systems Manager ★ オンプレマシンもAWSの仕組みで 管理できる(雑) ○ agentを動かして、登録。 32

Slide 33

Slide 33 text

AWS Systems Manager ★ Run Command ○ 管理サーバ上でスクリプトを実行可能。 ○ 対象をタグで一括指定。 ○ CircleCIから以下を実行している。 33 aws ssm send-command \ --document-name "Our-Deploy" \ --parameters "{\"tag\":[\"$VERSION\"]}" \ --timeout-seconds 600 \ --max-concurrency "50" \ --targets Key=tag:Deployable,Values=Yes \ Key=tag:Environment,Values=Staging \ ...

Slide 34

Slide 34 text

Blue-Green Deploy ★ 無停止デプロイへの課題 ○ コンテナを入れ替える必要 ○ コンテナポートをEXPORTする場合は、リバ プロ側の設定を変更する必要。 ■ リバプロ側のリロード処理も必要。 実行タイミング調整悩ましい。 ○ Docker Swarmとか、k8sとか大掛かりな物 を導入したくなかった。 ■ どのみちECSを目指しているし。 34

Slide 35

Slide 35 text

Blue-Green Deploy ★ LVSを採用 ○ Linux Virtual Server ○ L4 Load Balancer ○ LVSが外向けにPORT (80) をLISTEN ○ パケットの転送先にコンテナを指定 ○ 新コンテナ起動後、health checkしてOKな ら、LVSに組み込む。 ○ 古いコンテナはLVSから外して、graceful shutdown。 35 Ask The Speaer でのご指摘。 同時に新旧混在があるので、これは Rolling Updateですね。正しくは。 資料はそのままにしておきます。

Slide 36

Slide 36 text

Blue-Green Deploy 36 リバプロ Appサーバ 旧イメージベースの コンテナ LVS upstream backend { server 192.168.3.14; server 192.168.3.15; ... } 192.168.3.14 PORT 80 PORT 80

Slide 37

Slide 37 text

Blue-Green Deploy 37 リバプロ Appサーバ 旧イメージベースの コンテナ LVS 192.168.3.14 PORT 80 PORT 80 新イメージベースの コンテナ PORT 80 起動確認

Slide 38

Slide 38 text

Blue-Green Deploy 38 リバプロ Appサーバ 旧イメージベースの コンテナ LVS 192.168.3.14 PORT 80 PORT 80 新イメージベースの コンテナ PORT 80

Slide 39

Slide 39 text

Blue-Green Deploy 39 リバプロ Appサーバ 旧イメージベースの コンテナ LVS 192.168.3.14 PORT 80 PORT 80 新イメージベースの コンテナ PORT 80

Slide 40

Slide 40 text

Blue-Green Deploy 40 リバプロ Appサーバ 旧イメージベースの コンテナ LVS 192.168.3.14 PORT 80 PORT 80 新イメージベースの コンテナ PORT 80 graceful shutdown (SIGWINCH)

Slide 41

Slide 41 text

❖ 背景 ❖ システムの動作まわり ❖ Docker Image ❖ CI/CD ❖ 開発環境 41 Agenda

Slide 42

Slide 42 text

開発環境(ローカルマシン) ★ 同じコンテナイメージを利用 ○ ここはまだ悩んでいる ★ docker-compose を利用 ○ 本番構成と同じ構成になるだけ近づける ために、リバプロコンテナ、fluentdコンテナ など、開発環境だけのコンテナイメージも 作成 ○ PHPソースは、ローカルディレクトリをマウ ントしてそれが動作するようにしている。 42

Slide 43

Slide 43 text

開発環境(ローカルマシン) ★ メールは、mailcatcherを利用して、実 際には送信されないように ○ これもコンテナなので、実際にノーマルな MTAがインストールされたコンテナに差し 替えることで、実際に送信できるようにもし ている。 43

Slide 44

Slide 44 text

まとめ 44

Slide 45

Slide 45 text

★ PHPコンテナを動かす際に実際に取 り組んだことを話しました。 ○ ひたすら泥臭く実装した感じです。 ○ AWS環境移行時のイメージが具体化さ せるということはできた。 ★ 何か参考にでもなれば幸いです。 45

Slide 46

Slide 46 text

ご清聴ありがとうご ざいました。 46