docker runでエラー 'No such file or directory'

さくらのDocker入門

Dockerの理解を深めるために、さくらのDocker入門を見ながら実際に手を動かしていきました。すると、早速理解できていないことに気づきました。

1
2
docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:5.7
docker run --name some-wordpress -e WORDPRESS_DB_PASSWORD=my-secret-pw --link some-mysql:mysql -d -p 8080:80 wordpress

この部分です。docker run--linkオプションの意味を理解していなかったので、手元にあるDocker実践ガイド--linkオプションの説明を探しました。

linkオプションについて

mw0001というコンテナの起動で--link mariadb0001:db0001オプションを利用しており、その説明は以下のようになっていました。

  • これから起動するコンテナmw0001は、稼働中のコンテナmariadb0001とリンクを張る
  • コンテナmw0001において、mariadb0001コンテナの環境変数を取得することができる
  • db0001はエイリアス名である
  • mw0001が取得できるmariadb0001コンテナの環境変数名には、エイリアス名を大文字にした文字列が付与される

ということなので、エイリアス名を大文字にしたDB0001をprefixとした環境変数として、mariadb0001コンテナの環境変数を取得できるのだろうことはわかりました。

上記の説明の次のページになんのためにlinkオプションを利用するのかが記載されていました。

Column linkとは

Dockerにおけるlinkは、単一のDocker環境内で稼働する複数のコンテナ間において、コンテナの環境変数を他のコンテナで利用する機能です。
コンテナは、起動するたびにIPアドレスなどが変わるため、コンテナ間で通信を行う際に、環境変数に定義されたIPアドレスやポート番号を環境変数に定義し、その環境変数を別のコンテナで利用できるようにします。

なるほど、そういう目的なのですね。実際に試してみます。

コンテナmariadb0001の作成

まず、MariaDBのコンテナを作成します。本にしたがって行いますので、ベースイメージはcentos:7.5.1804となります。

yumリポジトリの追加

MariaDBの最新版を導入するため、リポジトリファイルを用意し、yum.mariadb.orgで提供されるリポジトリを使えるようにします。

1
2
3
4
5
[mariadb]
name = MariaDB
baseurl = http://yum.mariadb.org/10.4/centos7-amd64
gpgkey=https://yum.mariadb.org/RPM-GPG-KEY-MariaDB
gpgcheck=1

書籍のbaseurlはアクセスできなかったので修正しました。

Dockerfileの作成

Dockerfileは書籍のものを記載(したつもりでした)。

1
2
3
4
5
6
7
8
9
FROM centos:7.5.1804
COPY MariaDB.repo /etc/yum.repos.d/MariaDB.repo
RUN yum update -y && yum install -y MariaDB-server MariaDB-client
COPY server.cnf /etc/my.cnf.d/
COPY mariadb.sh /mariadb.sh
RUN chmod +x /mariadb.sh
VOLUME ['/var/lib/mysql']
EXPOSE 3306
ENTRYPOINT ['/mariadb.sh']

Dockerfileに記載のENTRYPOINTのシェルを準備したり、MariaDBの設定ファイルの準備も行いました。

イメージのビルド

では早速imageをbuildします。Dockerfileがあるディレクトリに移動し、以下のコマンドを実行します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
$ docker image build -f Dockerfile -t centos:mariadb0001 .
Sending build context to Docker daemon 6.144kB
Step 1/9 : FROM centos:7.5.1804
---> cf49811e3cdb
Step 2/9 : COPY MariaDB.repo /etc/yum.repos.d/MariaDB.repo
---> a5c6607df1f1
Step 3/9 : RUN yum update -y && yum install -y MariaDB-server MariaDB-client
---> Running in 8b498184156d

(中略)

Complete!
Removing intermediate container 8b498184156d
---> 95b6c03d5190
Step 4/9 : COPY server.cnf /etc/my.cnf.d/
---> d6c1d2ece48a
Step 5/9 : COPY mariadb.sh /mariadb.sh
---> 16c33f1ca0ad
Step 6/9 : RUN chmod +x /mariadb.sh
---> Running in 292c931ba940
Removing intermediate container 292c931ba940
---> 42e1af28711d
Step 7/9 : VOLUME ["/var/lib/mysql"]
---> Running in 67b800c69838
Removing intermediate container 67b800c69838
---> 2a0b5d4f6f3d
Step 8/9 : EXPOSE 3306
---> Running in ec0143ebd8db
Removing intermediate container ec0143ebd8db
---> ee16c6003675
Step 9/9 : ENTRYPOINT ["/mariadb.sh"]
---> Running in 21382026dc44
Removing intermediate container 21382026dc44
---> 8b9c2c536dc1
Successfully built 8b9c2c536dc1
Successfully tagged centos:mariadb000

ということで、無事ビルドできました。

コンテナの起動

ビルドしたイメージからコンテナを起動します。

1
2
$ docker run -d -e DBNAME=testdb -e MARIADBUSER=root -e MARIADBPASSWORD=mysqlPassword -v /var/lib/mysql:/var/lib/mysql:rw --name mariadb0001 centos:mariadb0001
1ad8c112f237ed46c442f90373ff11d126753b930703f81caa6b3b8f6b6c2620

起動したコンテナのIDが返ってきました。

無事起動できていると思いきや

1
2
3
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1ad8c112f237 centos:mariadb0001 "/bin/sh -c ['/maria…" 3 seconds ago Exited (127) 3 seconds ago mariadb0001

Exited…止まってしまっています…

起動しない原因の調査

まずはログをみてみます。

1
2
$ docker logs 1ad8c112f237
/bin/sh: [/mariadb.sh]: No such file or directory

DockerfileでCOPYしているはずのファイルがないと言われています。そんなはずはないと思って、なんどか再ビルドしたりしてみましたが全く変化がありません。

検索して出てくる結果は、docker image buildのタイミングでNo such file or directoryエラーが出るというものばかりで、docker container runのタイミングでエラーになるケースは見当たりません。

エラーの原因

もう一度Dockerfileをよくみてみました。すると、書籍はファイルパスがダブルクォートで括られていましたが、自分のDockerfileはシングルクォートになっていました。

もしやと思ってダブルクォートに変更後、再ビルド→起動してみると、無事起動しました!

1
2
3
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
65b5af36d7ac centos:mariadb0001 "/mariadb.sh" 20 seconds ago Up 19 seconds 3306/tcp mariadb0001

ダブルクォートで記載しないといけない点に関しては公式ドキュメントにも記載がありました。
こちらの下の方に注釈があり、その中で記載されています。

1
2
exec 形式は JSON 配列として解釈されます。
したがって文字列をくくるのはダブルクォート(")であり、シングルクォート(')は用いてはなりません。

なるほど、JSONなのですね、JSONでは文字列を括るのはダブルクォートでないとエラーになってしまいます。そういうことなのですね。

まとめ

Dockerfileでのexec形式([]で引数を取るパターン)では、文字列をダブルクォートで括るということを忘れないようにします。

次回はちゃんとlinkのテストを行いたいと思います。

その他

この調査でよく使ったコマンド

  • docker container prune
    止まっているコンテナを一括削除

  • docker ps -a
    全てのコンテナの一覧表示

  • docker logs <コンテナID>
    コンテナのログを出力する。エラーが起こった時には真っ先に確認する

  • docker image rm <イメージ名>
    指定したイメージを削除する