何をするか?
VPS などで Web アプリをホスティングする場合、各種サーバーを Docker コンテナとして立ち上げるようにすると OS 環境をクリーンに保てます。 特に、1 つのホスト(VPS サーバー)で複数の Web アプリを提供するような場合は、各アプリをコンテナで構成することで、関係ないアプリの設定が混ざってしまうのを防げます。 もちろん、Azure Container Instances や AWS Fargate といったコンテナ実行用のクラウドサービスを使えば、より独立した環境を構築できるのですが、これらのサービスは個人が趣味で使うにはまだまだ高価なので、VPS などの環境で Docker コンテナを立ち上げることには価値があります。
ここでは、Nginx サーバーを Docker コンテナとして立ち上げる方法を示します。
Docker Hub で公開されている Nginx イメージ は、デフォルトでコンテナ内の /usr/share/nginx/html ディレクトリに配置されたコンテンツを公開するようになっています。
大きく分けて、次の 2 つのいずれかの方法で簡単にコンテンツを公開できます。
- bind マウントで Docker ホスト側のコンテンツを参照する方法
- コンテンツを含んだコンテナイメージを作成する方法
以下、それぞれの方法を順番に見ていきます。
bind マウントで Docker ホスト側のコンテンツを参照する方法
Nginx のコンテナを起動するときに、Docker ホスト側のコンテンツディレクトリを bind マウントして、コンテナの /usr/share/nginx/html ディレクトリとして参照できるようにする方法です。
まず、簡単なコンテンツファイルとして次のような HTML ファイルを用意しておきます。
<html>Hello</html>あとは、docker container run コマンドで nginx コンテナを起動するだけです。
$ docker container run --rm -d -p 8000:80 -v "$(pwd)/public":/usr/share/nginx/html --name web nginx
各引数は次のような意味を持っています。
--rm… コンテナ停止時にコンテナを削除します。-d (--detach)… コンテナをバックグラウンドで動作させることで、現在の端末を引き続き利用できるようにします。-p 8000:80… ホスト側のポート 8000 へのアクセスをコンテナのポート 80 へ転送します。これにより、http://localhost:8000で Web サイトにアクセスできます。-v ...… ホスト側のカレントディレクトリにあるpublicディレクトリを、コンテナ側から/usr/share/nginx/htmlとして見えるようにバインドマウントします。バインド時のパスは絶対パスで記述しないといけないので、Linux シェルの機能の$(pwd)を使って、カレントディレクトリの絶対パスを取得しています。ちなみに-vオプションは旧式のやり方で、Docker 公式で推奨されている--mountオプションを使うと次のようになります(バインドマウントであることが明確です)。--mount type=bind,src="$(pwd)/public",dst=/usr/share/nginx/html--name web… 起動するコンテナにwebという名前を付けます。必須ではありませんが、名前が付いているとdocker container stop webでコンテナ停止できたりして便利です。nginx… Docker Hub からnginx:latestイメージを取得するよう指定しています。本番環境では、nginx:1.23のようにバージョンタグまで指定した方がよいでしょう。
無事コンテナが起動したら、次のように動作中であることを確認できます。
$ docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
dd4b471044b1 nginx "/docker-entrypoint.…" 2 minutes ago Up 2 minutes 0.0.0.0:8000->80/tcp, :::8000->80/tcp web
あとは、Web ブラウザや curl コマンドで http://localhost:8000 にアクセスできれば成功です!
$ curl localhost:8000
<html>Hello</html>
最後にコンテナを停止して後片付けします。
$ docker container stop web
コンテンツを含んだイメージを作成する方法
コンテンツディレクトリの内容を埋め込んだコンテナイメージを作成する方法です。
ここでも、上記と同様に public/index.html というコンテンツファイルを用意します。
イメージを作成するための Dockerfile を次のような感じで作成します。
FROM nginx:1.23
COPY public /usr/share/nginx/htmlDockerfile をビルドして、web という名前のイメージを作成します。
$ docker image build -t web .
イメージが作成できているか確認します。
$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
web latest 1e2497edf7e0 3 minutes ago 142MB
nginx 1.23 41b0e86104ba 30 hours ago 142MB
あとは、このイメージでコンテナを起動すれば OK です。
今回は、nginx イメージではなく、独自に作成した web イメージを使って起動することに注意してください(最後の部分が nginx から web に変わっています)。
$ docker container run --rm -d -p 8000:80 --name web web
先ほどと同様に、http://localhost:8000 にアクセスできれば成功です。
このやり方は、作成したイメージをそのまま別の Docker 環境で実行できるというポータビリティがありますが、コンテンツを変更したときはイメージの再ビルドが必要になります。
最後にコンテナを停止してお片付けしておきます。
$ docker container stop web
(おまけ)Docker Compose を使う
Docker Compose を使う と、docker container run ... の長いコマンドを入力せずに docker compose up という短いコマンドでコンテナを起動できるようになります。
また、Docker Compose はイメージのビルド機能も備えており、Dockerfile を用いたイメージのビルドからコンテナの起動までをワンステップで実行できます。
バインドマウントを使う場合の Compose ファイル (docker-compose.yml) は次のような感じで作成します。
内容は docker container run で指定したオプションとほぼ同様なので、簡単に理解できると思います。
version: "3"
services:
web:
image: nginx:1.23
volumes:
- ./public:/usr/share/nginx/html
ports:
- "8000:80"あとは、この docker-compose.yml ファイルがあるディレクトリで、次のように実行すればコンテナを起動できます(-d オプションを付けるとバックグラウンド実行になります)。
$ docker compose up -d
コンテナを停止&削除するときは、次のようにします(down の代わりに stop を使うと、コンテナの停止だけで削除されません)。
$ docker compose down web
Dockerfile からイメージをビルドして、そのイメージでコンテナ起動する場合は、Compose ファイルを次のように記述します。
イメージ名を指定する image: nginx:1.23 の代わりに build: . を指定して、カレントディレクトリの Dockerfile をビルドするように指示しています。
version: "3"
services:
web:
build: .
ports:
- "8000:80"あとは、同様に次のように実行すれば、イメージのビルドからコンテナの起動まで一気に終わります。ステキ!
$ docker compose up -d
関連記事
- Docker で Ansible の実行環境用のコンテナを作成する
- Let's Encrypt certificate expiration notice が来たら
- Nginx で 403 Forbidden エラーが出るときのチェック項目
- Nginx の設定: http でアクセスされた場合に https にリダイレクトする
- Sakura VPS レンタルサーバーを Let's Encrypt で SSL 対応
- Nginx の設定: Nginx の設定ファイルの書き方が正しいか確認する (configtest, nginx -t)
- Nginx の設定: Nginx の設定ファイルの変更を反映する (nginx reload)