かきノート

【Docker】Amazon Linux のコンテナ(AWS公式)を使って開発環境を構築したら、EC2 デプロイのアプリは幸せになれるんじゃ無いかと思ったが、見事に頓挫した

April 25, 2022 • ☕️ 7 min read

こんな環境で開発していました。

【 環境 】

ローカルの開発では Docker コンテナを使う。
Docker Compose を使い、PHP・Node.js・MySQL・Nginx・Redis が動いている。
フレームワークは Laravel と Vue.js。

Webアプリケーションは EC2 にデプロイ。
EC2 インスタンス内で、Laravel と Vue.js が動くようにする。

EC2 は2台用意し、ロードバランサで負荷を分散。

その他の AWS のリソースは、VPC・Route 53・RDS・ElastiCache といったサービスを使用した、ごく普通の構成。

本番環境・ステージング環境・開発環境と、同環境を3つ用意。

EC2 に実施する内容

EC2 には PHPおよび各種PHPモジュール、Composer でインストールできないモジュールについては個別にインストール。
あとは Node.js や Nginx、git や AWS CLI といった、実行環境を用意するために必要なツールを入れていく。

EC2 を1つ1つにアクセスして手作業でやるのが面倒なので、シェルスクリプトを用意して、コマンド一発で環境が整うようにしたい。

当初は Ansible で構成管理をしてみようかと思ったのですが、想像以上にツラかったので、シェルスクリプトで書く事にしました。

その時の記録がこちら。
Ansible って結構ツラいんじゃないかと思った話

Amazon Linux の公式 Docker を土台に、スクリプトを用意してみる

こういった作業は、一回で上手く行く事の方が珍しく、何度かトライアンドエラーを繰り返してようやく完成する、といったケースが圧倒的に多いです。
というか自分はそのパターンしか経験した事がありません。

実験用の EC2 インスタンスを作成し、トライアンドエラーを繰り返しながらスクリプトを作成し、完成したら破棄、というステップでも出来るのですが、インスタンスを起動して色々実験して上手くいかない部分が出てくると、ハマッた時間の分だけ課金されるのが嫌だったので、実験用のスクリプトはローカルに用意できないかと考えてみました。

すると、こんなのを見つけました。
https://hub.docker.com/_/amazonlinux

何と、AWS 公式の Amazon Linux コンテナイメージ!

docker-compose.yml をこんな感じで書けば、Amazon Linux が起動してくれるという、夢のような代物。

services:
  amazonlinux:
    image: amazonlinux:2

PHP のコンテナは php:8.0-fpm、Node.js のコンテナは node:16-slim と、どちらも Debian 系ですが、Amazon Linux は RedHat系です。

ディストリが異なるため、環境構築の方法が異なり、その差で余計なハマりポイントや上手くいかない部分に遭遇するのは、よくあるのではないかと思います。

が、公式が Amazon Linux のコンテナイメージを配布しているのであれば話は別だ。
php:8.0-fpm や Node.js、および nginx のコンテナを用意せず、Amazon Linux のコンテナに全部ブッ込む。
開発環境用に作成したスクリプトは、そのまま AWS環境にも適用できるので、環境の差異による予想外のエラーは完全回避可能!

おお!これは幸せな未来が見えるんじゃないか!
こんな幸せロードが見えてるのに、何で AWS は Amazon Linux の公式イメージを配布している事をもっとアピールしてくれないんだよ!もう全部コンテナで済ませろって事なのか!? いや、コンテナはコンテナでつらみがあるし、まだまだ EC2 の出番は多いのに!
と思いながら進めてみるものの、ものの見事に失敗し、最終的には頓挫しました。

以下、失敗して諦めるまでの記録です。

原則:コンテナ1つにつき、1プロセス

異変に気づいたのは Nginx をインストールして動かし始めた時でした。

この手のサービスを触る時、systemctl コマンドを頻繁に使いますが、コマンドを実行すると、「Failed to get D-Bus connection: Operation not permitted」というメッセージが表示されます。

調べてみると、CentOS だと docker-compose.yml に “privileged: true” を書いておけば実行できる事がわかるものの、Amazon Linux ではその方法では上手くいかず。

色々試してみても、泥沼にハマるばかりで全く解決の糸口が見えないばかりか、こういう情報まで見つかりました。

Dockerコンテナを特権モードで実行することが危険な理由 | トレンドマイクロ セキュリティブログ

Docker の「Privileged(特権)」コンテナ(以下、特権コンテナ)は、簡潔に言えば、ホストコンピュータに対するすべてのルート権限を備えたコンテナであり、通常のコンテナではアクセスできないリソースへのアクセスが可能となります。

■特権コンテナの問題点
一般に、「Docker-in-Docker」は、コンテナの実行中にもう一つ別のコンテナを生成する必要がある場合に使用されます。
ただし、保護をせずに特権コンテナを使用した場合、いくつかの深刻な影響が懸念されます。

とにかくやべー代物らしい。
Qiita や Zenn といった個人が好き勝手書くようなサイトではなく、セキュリティのスペシャリストが集まる会社の公式ブログなので、信憑性は極めて高いと思われます。

とりあえず、ECS や EKS では使ってはならないという事が分かりました。

それなら AWS上で使う事を前提とする Amazon Linux では、“privileged: true” を設定しても、それが有効にならない、というのは十分に考えられます。

ローカルで使うだけなら何とか行けるか?と思い、色々試してみるも、出てくるのはエラーメッセージばかりでどうにも上手く行かず。

出てくるエラーメッセージがプロセスがどうこうという内容だったので、「そういえば、Docker って、プロセス単位で動いているんだっけ。」と、Docker の超基本的な内容をふと思い出す。

という事で、「そもそも、自分は Docker の使い方が間違っていたのでは?」と立ち戻って調べ直してみたところ、こんなのが見つかりました。

1コンテナ複数プロセスはやめておいた方が良い話

Docker コンテナの原則として「1コンテナ1プロセス」1というものがありますが、あえてこの原則を破りたいときがあるかもしれません。 そんな時は、以下の Docker 公式ドキュメントを参考にすると、良いでs……死にます。

コンテナー内での複数サービス起動 | Docker ドキュメント

アプリケーションが持ついくつもの役割を 1 つのコンテナーに持たせることは、Docker の優れた機能を利用する観点からは避けるべきです。

という事で、他にも人柱が立っておりました。
また、Docker のベストプラクティスからも、1コンテナ1プロセスで、1つのコンテナに複数の役割を持たせる事は推奨していません。

やろうと思えばできないこともないけど、結構色々と変な事をしなければならない上、セキュリティ上の理由および動作の安定性から本番環境では使い物にならない、といった感じです。

という事で、Amazon Linux に色々載せて開発環境を構築する方針は、見事に頓挫しました。

あとがき

この事を知人に話してみました。

AWS 公式の Amazon Linux コンテナイメージを配布しているという事を話した時点では彼もテンションが上がり、「もう、開発環境は全部これ使えばいいじゃないですか!」と興奮気味に話を聞いてくれたものの、結末を話したら、「え?じゃあこのコンテナ、何に使うんですか?」といった反応でした。

俺もそう思う。
何に使うんだ。このコンテナイメージ。

期待を膨らませて張り切って突き進んでみたものの、変なトラップ踏んで無駄に時間溶かしただけだった。


Relative Posts:

【Amazon Linux】 GitHub CLI のインストールを諦めました

April 23, 2022

福岡の物流エンジニアが、七転び八起きしたあと九回転び、寝っ転がったまま何かやってる事を垂れ流しているブログ

RotateLinkImg-iconRotateLinkImg-iconRotateLinkImg-iconRotateLinkImg-icon