前回の続きです。
参考にさせていただきました。
zenn.dev
note.com
今回はDocker Composeを使うので構築まであれこれ試行錯誤はしたものの、記事にすると手順自体はdocker-compose.ymlをぺたりと貼るだけのところに着地します。
DockerfileとDocker Compose
Dockerのサイトによると、
Dockerfileは「イメージを自動で作成するためのコマンドを含んだテキストファイル」という感じでしょうか。
Docker can build images automatically by reading the instructions from a Dockerfile. A Dockerfile is a text document that contains all the commands a user could call on the command line to assemble an image. This page describes the commands you can use in a Dockerfile.
Docker Composeは「複数コンテナーのDockerアプリケーションを定義して実行するためのツール」ということですかね。
Compose is a tool for defining and running multi-container Docker applications. With Compose, you use a YAML file to configure your application’s services. Then, with a single command, you create and start all the services from your configuration.
というわけで文章だけ見ると複数のコンテナを使う場合だけDocker Composeを使い、単一の場合にはDockerfileを使うと良いみたいに取れますが、実際には単一のイメージを使う場合にもDocker Composeは便利ですし、DockerfileとDocker Composeを組み合わせて使うこともよくあるようです。
どちらかというとDockerfileはイメージを作る作業を自動化したもので、Docker Composeは作ったイメージをどういう設定で動かすか指定するものくらいでいいんじゃないでしょうか。
もちろんその中に複数イメージをどう連携させるかっていう話も入ってくるのですが…。
今回はイメージは基本的に配布されているものをそのままで、dockerコマンドの引数的なものを全部Docker Composeに入れるようなイメージで作っていきます。
ネットワークを作る
docker-compose.ymlにサービスを複数書くと勝手にネットワークができてコンテナ間の参照ができます。
が、今回は1つのサービスとして全部セットでdocker-compose.ymlに書く方式は取らないため、普通にネットワークを作ってそこに参加させる方式を取ります。
ひとまずDBを参照できるネットワークとnginxを経由してHTTPアクセスできるWebのネットワークを作成します。
とりあえず既存のネットワークを見てみると、何もないかと思いきや「bridge」「host」「none」の3つのネットワークが最初からあります。
これらについては詳しく解説してくれているサイトなどがあるので特には触れません。
$ docker network ls NETWORK ID NAME DRIVER SCOPE 440f88691de8 bridge bridge local c9d361d10742 host host local 92c07b77e335 none null local
DB用とWeb用のネットワークを作りました。何も指定しないとbridgeネットワークになります。
$ docker network create db_network $ docker network create web_network $ docker network ls NETWORK ID NAME DRIVER SCOPE 440f88691de8 bridge bridge local 46521ed7ae0a db_network bridge local c9d361d10742 host host local 92c07b77e335 none null local 6ea3a2e26663 web_network bridge local
docker-compose.ymlを書く
まず好きなところにディレクトリを作ります。
作ったディレクトリにdocker-compose.ymlを置きます。
はい。
version: '3.8' services: mysql: image: mysql: 8.0.32 container_name: mysql ports: - 3306:3306 environment: TZ: "Asia/Tokyo" MYSQL_ROOT_PASSWORD: root MYSQL_DATABASE: db MYSQL_USER: docker MYSQL_PASSWORD: docker volumes: - ./data:/var/lib/mysql networks: - db_network networks: db_network: external: true
ちょっと解説。
servicesの下に登録したいサービスを書きます。複数書いたら複数同時にコンテナを立ち上げられます。
imageにはDockerImageを指定します。Dockerfileを指定する場合はbuildを使います。ここでは省略。
container_nameはコンテナ名です。docker psで表示されるコンテナ名や、他のコンテナから参照するときの名前です。
portsはホスト側のポートとコンテナ内のポートを繋ぎます。この例だとホストの3306ポートへのアクセスはこのコンテナに転送されます。(アプリケーションで使うだけならホスト側にポートを繋ぐ必要はないかもしれませんが、普通に中身が見たいので設定)
environmentは環境変数です。利用したいDockerImageごとに使うものはバラバラですが、ここに初期値を与えることでコンテナ起動時に色々勝手にやってくれることが多いです。(MySQLの場合はrootのパスワードや初期作成するDBの情報が書けます。複数DB作るのはDockerfileでやってねってことかな…?)
volumesはボリュームのマウント設定です。ホスト側のディレクトリをコンテナ内に繋ぐときに使います。後ろに「:ro」をつけると読み取り専用になります。
networksは参加させるネットワーク名です。今回は既に作成してあるdb_networkを使います。(外にあるネットワークなのでexternal: trueが必要)
で、はい。
version: '3.8' services: nginx: image: nginx:1.23.3 container_name: nginx ports: - 80:80 environment: TZ: "Asia/Tokyo" volumes: - ./config/default.conf:/etc/nginx/conf.d/default.conf - ./log:/var/log/nginx - ./html:/var/www/html networks: - web_network networks: web_network: external: true
設定をいじったり、ログを外側に吐いたり、htmlを置いたりできるようにマウントしているくらいですかね。
default.confは一旦こんな感じでマウント元のディレクトリにおいておきます。
とりあえず./htmlにindex.htmlとか置くと見れます。他にはなんのアプリケーションもないので404。
server { listen 80; # IPv4 listen [::]:80; # IPv6 server_name ubuntu-server; # 受け付けるホスト # なんかもろもろのヘッダ proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-Port $server_port; root /var/www/html; # 静的ページのroot # 400番台エラーのハンドリング(root上書きしてるので戻す) error_page 404 /404.html; location = /40x.html { root /usr/share/nginx/html; } # 500番台エラーのハンドリング error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } }
これでそれぞれのディレクトリで以下のコマンドを叩くとコンテナが立ち上がります。
$ docker compose up
が、フォアグラウントで実行しても困るので、バックグラウンドで実行する場合はdオプションを付けます。
$ docker compose up -d
バックグラウンドだとログとか何も見えないので、ログが見たい場合には「docker logs」コマンド。
$ docker logs nginx ~(略)~ /docker-entrypoint.sh: Configuration complete; ready for start up
これでDBを使うときはdb_networkに、nginxの裏側でWebサービスを公開する場合にはweb_networkに繋げばOKという状態になりました。