🐳

『実践 Docker - ソフトウェアエンジニアの「Docker よくわからない」を終わりにする本』をやって詰まったところ

2022/04/23に公開

VSCodeのdevcontainerで開発環境を整えることができるようになってから、私もその流れに乗って、個人の開発はdevcontainerでやってきましたが、少し使ってみると自分のDockerへの理解の浅さからか、思ったように開発環境が作れないといった事象が出てきました。

なので、Dockerをちゃんと学んでみたいと思い、色々調べたところ、Zennでほげさんという方が、無料でDockerについての入門書を公開してくださっており、こちらを頭からやってみました。

https://zenn.dev/suzuki_hoge/books/2022-03-docker-practice-8ae36c33424b59

コマンドの説明だけではなく、仮想化とは?というところから説明しており、タイトルにもある通り「よくわからない」という状態から抜け出すのにはぴったりな本だと感じました。
2022年4月現在では無料なので、Docker周辺の知識について不安な点がある方は、是非一度読むことをオススメします。

しかし、ほげさんとの環境差分からか、ハンズオンの中で詰まったポイントがあったので、書き留めておきます。

今後、この本に取り組まれる方の助けになれば幸いです。

ちなみに、私の開発環境は以下のとおりです。

  • OS : Windows10
  • Docker version : 20.10.7
  • ターミナル : VSCodeのbash

mount path must be absolute.

3部:ボリュームのあたりで、以下のようなコマンドが出てきます。

掲載されているコマンド
$ docker container run                                                   \
    --name db                                                            \
    --rm                                                                 \
    --detach                                                             \
    --platform linux/amd64                                               \
    --env MYSQL_ROOT_PASSWORD=rootpassword                               \
    --env MYSQL_USER=hoge                                                \
    --env MYSQL_PASSWORD=password                                        \
    --env MYSQL_DATABASE=event                                           \
    --mount type=volume,src=docker-practice-db-volume,dst=/var/lib/mysql \
    docker-practice:db

これを私の方で打ってみると、以下のようなエラーが出ました。

docker: Error response from daemon: invalid mount config for type "volume": invalid mount path: 'C:/Program Files/Git/var/lib/mysql' mount path must be absolute.

どうやら、ボリュームのマウント先を指定するdst=/var/lib/mysqlのパスが、ホストマシンの相対パスだと思われているようです。

色々調べてみると、こんな記事が出てきました。

https://fukuchiharuki.me/static/pukiwikidump/page/障害メモ/Docker for Windowsでボリュームマウントできない.html

これを参照して、パスの指定を//から始めるように変更

変更後
$ docker container run                                                   \
    --name db                                                            \
    --rm                                                                 \
    --detach                                                             \
    --platform linux/amd64                                               \
    --env MYSQL_ROOT_PASSWORD=rootpassword                               \
    --env MYSQL_USER=hoge                                                \
    --env MYSQL_PASSWORD=password                                        \
    --env MYSQL_DATABASE=event                                           \
    --mount type=volume,src=docker-practice-db-volume,dst=//var/lib/mysql \
    docker-practice:db

上記のコマンドに変更してみると、コンテナが作成されました。

init.sqlというディレクトリが作成されてしまう。

3章:バインドマウントにて、DBの初期化クエリをバインドマウントしてコンテナに配置するというコメントがあります。

$ docker container run                                                                       \
    --name db                                                                                \
    --rm                                                                                     \
    --detach                                                                                 \
    --platform linux/amd64                                                                   \
    --env MYSQL_ROOT_PASSWORD=rootpassword                                                   \
    --env MYSQL_USER=hoge                                                                    \
    --env MYSQL_PASSWORD=password                                                            \
    --env MYSQL_DATABASE=event                                                               \
    --mount type=volume,src=docker-practice-db-volume,dst=/var/lib/mysql                     \
    --mount type=bind,src=$(pwd)/docker/db/init.sql,dst=/docker-entrypoint-initdb.d/init.sql \
    docker-practice:db

これを実行して、コンテナに入ってテーブルを調べてみると、テーブルが作成されておりません。
コンテナ内の/docker-entrypoint-initdb.dを調べてみると、init.sqlというディレクトリが作成されていました。

これに関しては、実行しているコマンドにも間違いはなかったので、なにかDockerの新仕様なのか??とかなり難しいところまで調べてしまいましたが、実際のところ原因はすごく単純でした。
/workディレクトリでコマンドを実行していなかったのです。

コマンド内の$(pwd)は、コマンドを実行しているディレクトリを指すため、そこから参照した時にinit.sqlが見つからず、Docker側で空のディレクトリが作成されてしまったというわけです。
きちんと/workディレクトリから実行した結果、初期化クエリが実行され、テーブルが作られていました。

実行するディレクトリは確認しないとなと思ったのと同時に、こういう環境構築を会社で行って、複数のメンバーに横展開するときには、各自のメンバーのディレクトリ構造などに依存しないような構成にしたいなとも思いました。

DBにログインできない

3部:Docker Composeにて、今までのコマンドをdocker-compose.ymlで再現する手順を説明してくれています。

最後まで手順を終え、docker compose upでコンテナを立ち上げて、アプリケーションを見てみると、トップページやメール送信のページは見えるものの、historyページが見えません。

エラーログを見てみると以下のようなメッセージが

PHP Fatal error:  Uncaught PDOException: SQLSTATE[HY000] [1045] Access denied for user 'hoge'@'172.28.0.4' (using password: YES) in /src/history.php:15

どうやらDBに接続できていないようです。

見直してみると、MySQLのログインパスワードにtypoがありました。

docker-compose.yml
  db:
    container_name: docker-practice-db
    build:
      dockerfile: docker/db/Dockerfile
      context: .
    environment:
      MYSQL_ROOT_PASSWORD: rootpassword
      MYSQL_USER: hoge
      MYSQL_PASSWORD: pasword
      MYSQL_DATABASE: event
    volumes:
      - type: volume
        source: docker-practice-db-volume
        target: /var/lib/mysql
      - type: bind
        source: ./docker/db/init.sql
        target: /docker-entrypoint-initdb.d/init.sql

これを修正して、docker compose up --buildでイメージのビルドからやり直しました。

docker-compose.yml(修正後)
  db:
    container_name: docker-practice-db
    build:
      dockerfile: docker/db/Dockerfile
      context: .
    environment:
      MYSQL_ROOT_PASSWORD: rootpassword
      MYSQL_USER: hoge
      MYSQL_PASSWORD: password
      MYSQL_DATABASE: event
    volumes:
      - type: volume
        source: docker-practice-db-volume
        target: /var/lib/mysql
      - type: bind
        source: ./docker/db/init.sql
        target: /docker-entrypoint-initdb.d/init.sql

しかし、まだ接続できていないようです。
docker container execでコンテナに入り、環境変数を調べても、何もおかしいところはありません。

# echo $MYSQL_ROOT_PASSWORD
rootpassword
# echo $MYSQL_USER
hoge
# echo $MYSQL_PASSWORD
password
# echo $MYSQL_DATABASE
event

どうしたものかと少し悩んだところ、DBのデータはvolumeにマウントされていることを思い出しました。

そこで、volumeを削除してから再ビルド。

$ docker volume ls
DRIVER    VOLUME NAME
local     work_docker-practice-db-volume

$ docker compose down
[+] Running 4/4
 - Container docker-practice-mail  Removed   0.9s 
 - Container docker-practice-db    Removed   0.9s 
 - Container docker-practice-app   Removed   0.9s 
 - Network work_default            Removed   0.1s

$ docker volume rm work_docker-practice-db-volume
work_docker-practice-db-volume

$ docker compose up --build

すると、無事にDBに接続できるようになり、historyページも見えるようになりました。

各ページの最後に、そこのページで作成したリソースの削除手順まで記載してくれていますが、それぞれのページで手順をやり直す際は、一度リソースをすべて削除してからやり直すことをオススメします。

まとめ

私が詰まった点は、大きく上記の3つです。

私の凡ミスもありましたが、本の最後にはデバッグノウハウも記載されていますし、きちんと最初から理解していけば、多少のつまずきポイントは自分で解消して進めることができるというのも実感として得られました。

冒頭にも申し上げましたが、まだこの本を見ていない方は、是非一度ご覧になってみてください。

最後になりますが、ここまで分かりやすい本を無料で公開してくださっているほげさん、有難う御座います!

Discussion