最終更新日

香川研究室での Docker の使い方

はじめに

Docker は OS レベルの仮想化技術を利用して、コンテナーと呼ばれる形式 でソフトウェアのパッケージを提供する技術です。コンテナー内で実行される プロセスは、他のプロセスやファイルシステムから隔離され、独自のファイル システもやプロセステーブルを持ち、あたかもそれ専用のコンピューターで実 行されているかのように見えます。

(ファイルやポートを共有するように起動時に設定しない限り)コンテナー 内で実行するプロセスは、コンテナー外のプロセスやファイルシステムに影響 を及ぼすことはありません。

Docker コンテナーは、OS 自体を実行するわけではないので、仮想マシンな どと比べると軽量で、一つのハードウェアでも多数実行することができます。

参考

Windows Subsystem for Linux 2 により、Windows 上でも手軽に Docker を実行で きるようになりました。

ここでは香川研究室で Docker を使用するときに、特に必要な事柄を説明します。

Dockerfile の書き方

Dockerfile は、Docker イメージを構築するための命令の集まりです。 Docker イメージは Docker コンテナーの土台・ひな型です。 Dockerfile を作成しておくと、Docker が動いている環境ならどこ でも、サーバー環境をコマンド一つで起動することができます。

卒業論文や修士論文の研究で作成したシステムにサーバー側のプログラムを含 んでいる場合は(例えば Java Servlet/JSP, node.js, PHP, WAI, Django, Flask, Ruby on Rails などで作成している場合は)Dockerfile を作成してお いて、サーバー側プログラムを、どのマシンにでも、すぐに配備できるように 準備しておいてもらえると、卒業・修了後に後輩が気軽に試せるようになりま す。 というわけで、サーバー側のプログラムを使っている場合は、Dockerfile も同時に用意するようにしてください。(また、同時にクライアント側のプロ グラムはソースの少数の箇所を書き換えるだけで、サーバー側の URL を変更で きるようにしておいてください。)

Dockerfile の命令には、元となるイメージの指定 (FROM)、ファイルの取得 (ADD, COPY)、コマンドの実行 (CMD)などがあります。詳しくは Dockerfile のリファレン スを見てください。 ここでは使用頻度の高い命令だけを紹介します。

FROM

作成する Docker イメージの元になるイメージ名を指定します。 C や Haskell をコンパイルしてできるバイナリーファイルを置くならば、 バイナリーファイルをビルドするのと同じ環境 (ubuntu など)を指定します。 Java や Kotlin のプログラムを動かすのならば ecliplse-temurin, sapmachine あるいは tomcat などが良いでしょう。 インタプリター方式の言語については python, node など、専用のイメージを探しましょう。

例:

Docker repository

Docker Hub の Browse Popular Images で、元にする Docker Image を探すことができます。例えば、Node.js を使うなら、オフィシャルイメージの node を使うことができます。

LABEL

maintainer="〜" として作成者のメールアドレスを指定します。

例:

RUN

任意のコマンドをイメージ上で実行します。 apt-get などのコマンドで、必要なソフトウェアをインストールするなどのときに使います。

例:

WORKDIR

以降で実行する命令の作業ディレクトリーを指定します。

例:

ADD と COPY

どちらもイメージにファイルを追加します。 ADD 命令と COPY 命令は似ていますが、 ADD 命令のほうは tar ファイルを展開できる、ソースとして URL を指定できる、 などの違いがあるようです。 COPY 命令は、ファイルやディレクトリーを文字通りコピーするだけです。 単なるファイルのコピーならば、単純なほうの COPY 命令を使うとよいでしょう。

例:

シンボリックリンクに関する Tips

Dockerfile 内の ADD コマンド、COPY コマン ドは、シンボリックリンクをたどりません。しかし、場合によっては、シンボ リックリンクをたどってほしいことがあります。そういうときは、build コマンドを実行するときに、以下のよう に tar コマンドと組み合わせると、シンボリックリンクをたどっ てくれます。

tar -czh . | docker build - -t tagname

参考: How to make a symlinked folder appear as a normal folder

ENV

環境変数を指定します。

例:

USER

以降の RUN などの命令を実行するユーザーとグループを指定します。

例:

VOLUME

マウントポイントを作成します。 コンテナーを docker コマンドで起動するときに -v オプションでホスト上のディレクトリーを マウントするときなどに使用します。

例:

EXPOSE

コンテナーを実行するときにリッスンするポートを指定します。 コンテナーを docker コマンドで起動するときに -p オプションでコンテナーのポートを公開するときに使用します。

例:

CMD

コンテナーが実行するコマンドを指定します。

例:

Docker 起動オプション

Docker コンテナー起動するときのコマンド(docker run)の よく使うと思われるオプションとして、次のようなものがあります。

-p
コンテナーのポートをホスト側のポートにバインドする
-v
ホスト側のファイルシステムをコンテナー側にマウントする
--restart
再起動ポリシーを指定する

例:

docker run -p 127.0.0.1:8080:80 -v /home:/home --restart unless-stopped imagename &

詳しくは、 docker run のコマンドライン・リファレンスを見てください。

NGINX との連携

Docker で配備したサーバー側のプログラムを、研究室の外にも公開する場 合、NGINX の Reverse Proxy の設定で 80 番ポートへのアクセスを Docker コンテナーのポートへ通過させる場合が多い と思われます。 詳しくは、香川研究室での NGINX の使い方 を見てください。

あるポートをサービスの待受けに使ったら、他の人が使ったポートと衝突しないように /etc/nginx/conf.d/default.conf の先頭に、コメントのカタチ でメモしておいてください。

また、ポートの代わりに Unix Domain Socket を使えば、ポートが誰か他の人と衝突しないか、 あまり、気にしなくても良くなります。 NGINX は Unix Domain Socket をサポートしています。 もちろん、サーバー側のプログラムも Unix Domain Socket で待ち受ける必要があります。

Jetty を始め、ほとんどのサーバー側フレームワークは Unix Domain Socket を サポート(参考: Class UnixSocketConnector)しています。 Warp も runSettingsSocket という関数で Unix Domain Socket をサポート(参考: Warp: Binding to Unix Domain Sockets)するようです。 もしサーバー側プログラムが Unix Domain Socket をサポートしてい ない場合は、コンテナーで socat などのプログラムを実行する という手段もあります。

socat UNIX-LISTEN:/path/to/socket,fork,user=www-data,reuseaddr TCP4:127.0.0.1:8080

Koji Kagawa