docker

Laravel Sail のプロジェクトを新規作成する際にDocker is not running. – Docker Desktop 再起動で改善

こんにちは、ウチイダです。

今日は、以前からたびたび発生しては時間を地味に奪っていくエラーについて。

Laravel Sail のプロジェクトを作成する際に、以下のようなエラーが出ます。

$ curl -s "https://laravel.build/laravel_app" | bash
Docker is not running.

そもそも、WSLからdocker コマンドが使えません。ソケットが開いてない?

$ docker ps
Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?

WSLの再起動をやってみても、解消したりしなかったり、だったのです。

しかし、最近試してみた方法で、すぐに直せることが分かったのでメモしておきます。

タスクバーからDockerのアイコンを右クリック > Restart する

以上です。

DockerDesktopを再起動するだけ

WSLを止めて起動しなおしたり、WSL側のDocker デーモンの動作を確認したりしてましたが、全然関係なかったみたいです。

発生する原因はわからないままなのですが、すぐに解消できるようになったので、しばらくこの方法で対応したいと思います。

以上、あなたのお役に立てれば幸いです。

Docker コンテナのリソース使用率を調べるのに便利なコマンド ctop

こんばんは、ウチイダです。

先日、Webアプリケーションのチューニングコンテストに参加しました。

パフォーマンスの計測とボトルネックの発見を担当したのですが、その際に使用したctop というコマンドが便利だったのでメモしておきます。

公式リポジトリはこちらです。

https://github.com/bcicen/ctop

WSL2 へのインストールは以下でできました。

$ sudo wget https://github.com/bcicen/ctop/releases/download/v0.7.1/ctop-0.7.1-linux-amd64  -O /usr/local/bin/ctop
$ sudo chmod +x /usr/local/bin/ctop

Docker コンテナの稼働状況をみたいのがウチイダの用途なので、–type オプションをつけて実行します。

$ ctop --type=docker

Laravel Sailのコンテナを立ち上げて、上記コマンドを実行すると、以下のようにモニタリングできます。

dtop –type=docker 実行結果

スクリーンショットだと見切れていますが、CGROUP のところにグループ名が書かれていて、どのコンテナかわかるようになっています。

上下キーでコンテナを選択して、 e キーでコンテナのターミナルをすぐ開けるのも便利です。

以上、あなたのお役に立てれば幸いです。

Laravel Sail でコンテナのshellを使う

こんばんは、ウチイダです。

Laravel Sail便利ですよね。docker-compose のラッパーみたいなものなので、学習コストも低くてとても良い感じです。

docker-composeでできることは何でもできるので、困ったらdocker-composeのコマンドを調べるのですが、なかなか覚えられません。

ちょくちょく使うのが、コンテナに入るコマンドです。

# Laravelアプリケーションのコンテナのbashを開く
$ docker-compose exec laravel.test bash

dockerコマンドみたいに、-it とかオプション付けなくてもいいので、まだいいですが、長いですよね。

あるときふとReadoubleを見直してみたら、sail コマンドからコンテナ接続するサブコマンドがちゃんと用意されていました。

# sail コマンドから、Laravel アプリケーソンのコンテナのbashをひらく
$ sail shell

# root ユーザーで接続する場合
$ sail root-shell

# Readoubleにはないけど、以下でもOK
$ sail bash

すごく短くなります。

sailコマンドの中身(vendor/bin/bash)は難しくないshellスクリプトなので、中身を見てみるといろいろ発見があって面白いです。

以上です。あなたのお役に立てれば幸いです。

WSL上のDocker Composeで作成したコンテナに、Windows 11ホストから接続する

こんにちは、ウチイダです。

ここしばらく、Windwos 11のWSL Ubuntu での環境構築を進めてきました。

前回の記事で、Docker Composeのインストールを紹介しています。

今回はその続きとして、シンプルなPHP開発環境をDocker Compose を用いて作成し、Windows ホストのブラウザからアクセスできるように設定していきます。

これができると、ついにWindows 11でWSLを使った実用的なWeb開発ができるようになります。

なお、動作環境は以下の通りです。

  • Windwos 11 Pro (21H2 ビルド 22000.120)
  • WSL カーネル バージョン: 5.10.16
  • Windows Terminal バージョン: 1.9.1942.0
  • Docker バージョン 20.10.8, build 3967b7d
  • Docker Compose バージョン 1.29.2, build 5becea4c

前準備①:Docker デーモンを起動する

WSLのディストリビューションは、サービスの自動起動などを行いません。

WSLを起動した後、最初にDockerを利用する場合は、デーモンを起動するのを忘れないようにしましょう。

$ sudo service docker start
[sudo] password for y-uchiida:
 * Starting Docker: docker                                 [ OK ]

## Docker デーモンの起動を確認します
$ service docker status
 * Docker is running

前準備②:開発環境をつくるディレクトリを作成

続いて、Docker に関するファイルや、PHPなどのスクリプトを置くディレクトリを作成します。

例として、「sample_docker-compose_on_wsl」を作成します。

また、PHPやJavaScriptなどのデータを置くための「public」も作成しておきます。

## とりあえずホームディレクトリに作ることにします
## 開発環境をまとめておく場所を決めている方は、そちらに作成してください
$ mkdir ~/sample_docker-compose_on_wsl

## 公開用ファイルを設置するpublic ディレクトリを作成します
$ mkdir ~/sample_docker-compose_on_wsl/public 

前準備③:ファイル編集とDocker実行の準備

この後の作業で、yamlファイルを編集したりdocker-compose コマンドを実行したりするので、作成した開発環境用のディレクトリに移動しておきます。

また、エディタも用意します。以下の例では、VS Codeでsample_docker-compose_on_wsl ディレクトリを開いています。

## docker-compose コマンドを使うので、カレントディレクトリを移動しておきます
$ cd ~/sample_docker-compose_on_wsl

## Visual Studio Code(VS Code) を利用している方は、code コマンドでVS Codeで開くことができます
## docker-compose.ymlの編集などはVS Code
$ code .

docker-compose.ymlを作成する

準備が整いましたので、Docker Compose でコンテナを生成・起動するためのファイル docker-compose.ymlを作っていきます。

sample_docker-compose_on_wsl ディレクトリ配下に作成します。

完成コードは以下です。

ディスク容量を圧迫しないように、alpine ベースのイメージを選択しました。

version: '3.8' # 現時点での最新のバージョンを指定しておきます
services: 

  # Webサーバとして、nginx を利用します
  web: 
    container_name: "web"
    image: nginx:1.21.1-alpine
    ports:
      - "8080:80" # ポート8080を、ポート80 へフォワーディングします
    links:
      - app # php 実行コンテナ(app)に接続できるようにします
    volumes:
      - ./public:/var/www/public # WSL側のpublic ディレクトリを、web コンテナにマウントします
      - ./default.conf:/etc/nginx/conf.d/default.conf # nginx の設定ファイルを、web コンテナにマウントします

  app:
    container_name: "app"
    image: php:7.4-fpm-alpine3.14
    volumes:
      - ./public:/var/www/public # web コンテナと同じパスにアクセスできるように、app コンテナにもpublic ディレクトリをマウントします

ここでのポイントは2点あります。

ひとつは、links でweb コンテナから app コンテナに接続できるように設定したことです。

これにより、phpファイルが呼び出された際にapp コンテナへ処理を引き渡すことができるようになります。

もうひとつは、web と app の両方の volumes に./publicをマウントするように記述したことです。

同じファイルパスで参照できるようになるので、スムーズに処理の引き渡しができます。

コンテナにマウントするファイルを作成する

続いて、コンテナにマウントするファイルを作っていきます。

最低限の用意として、2つのファイルを作成します。

phpの処理をapp コンテナに引き渡すための設定を記述したnginxのconfigファイル「default.conf」と、publicルートにアクセスした際に処理される「index.php」です。

default.confの作成

まずは、nginxの設定ファイルから見ていきます。

sample_docker-compose_on_wsl ディレクトリの直下に、以下のdefault.conf を作成してください。

server {
    listen 80;
    server_name localhost;

    root /var/www/public;
    index index.php;

    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;

    # PHP ファイルへアクセスされた場合に、app コンテナのfast CGIへ処理を回します
    location ~ \.php$ {
        include fastcgi_params;

        # app コンテナのポート9000でFast CGI がListenしているので、そちらへパスします
        fastcgi_pass app:9000;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_index index.php;

        # nginx がアクセスされたファイルパスを、app コンテナで処理すべきファイルパスとして渡します
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;

        try_files $uri = 404;
    }
}

ポイントは、 location ~ \.php のディレクティブです。

ここで、php ファイルにアクセスされた際にapp コンテナへ処理を移すための設定を記載しています。

app コンテナのポート9000でFast CGI がListenしているので、fastcgi_pass はapp:9000 を指定します。

また、SCRIPT_FILENAME で、nginx がアクセスされたファイルパス($dcoument_root$fastcgi_script_name)を渡しています。

docker-compose.yml では、2つのコンテナにpublic ディレクトリを同じパスにマウントしました。

コンテナ同士のphpファイルのパスを一致させているため、このように記述できます。

index.php の作成

最後に、index.php を作成します。

これは、phpが動作していることが分かれば何でもよいです。

public ディレクトリ内に作成します。

<?php
    echo "hello from docker on wsl!!<br>\r\n";

内容は、好きなように設定してください。

コンテナの起動と動作確認

準備が整いましたので、docker コンテナを起動して動作を見ていきます。

まずはコンテナの起動です。

## dockerコンテナの起動には、sudo が必要になると思います
## コンテナ起動後にほかのコマンドを使いたいので、最後に & をつけてバックグラウンドで処理させます
$ sudo docker-compose up &
Creating app ... done
Creating web ... done
Attaching to app, web
app    | [09-Aug-2021 09:19:39] NOTICE: fpm is running, pid 1
app    | [09-Aug-2021 09:19:39] NOTICE: ready to handle connections
web    | /docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
web    | /docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
web    | /docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
web    | 10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
web    | 10-listen-on-ipv6-by-default.sh: info: /etc/nginx/conf.d/default.conf differs from the packaged version
web    | /docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
web    | /docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
web    | /docker-entrypoint.sh: Configuration complete; ready for start up
web    | 2021/08/09 09:19:40 [notice] 1#1: using the "epoll" event method
web    | 2021/08/09 09:19:40 [notice] 1#1: nginx/1.21.1
web    | 2021/08/09 09:19:40 [notice] 1#1: built by gcc 10.3.1 20210424 (Alpine 10.3.1_git20210424)
web    | 2021/08/09 09:19:40 [notice] 1#1: OS: Linux 5.10.16.3-microsoft-standard-WSL2
web    | 2021/08/09 09:19:40 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576
web    | 2021/08/09 09:19:40 [notice] 1#1: start worker processes
web    | 2021/08/09 09:19:40 [notice] 1#1: start worker process 32
web    | 2021/08/09 09:19:40 [notice] 1#1: start worker process 33
web    | 2021/08/09 09:19:40 [notice] 1#1: start worker process 34
web    | 2021/08/09 09:19:40 [notice] 1#1: start worker process 35

コンテナ起動時のメッセージがたくさん出ます。最後にstart worker process (番号) と表示されれば成功です。

コンテナの起動コマンドの最後に 「&」 をつけておくと、コンテナの起動がバックグラウンドで処理されます。

バックグラウンド処理にしておくことで、up コマンド実行後も同じターミナルで別のコマンドが実行できます。

WSLからコンテナにアクセス

まずはDocker コンテナのホストであるWSL から、コンテナへアクセスしてみます。

8080ポートをフォワーディングしているので、localhost:8080でコンテナ内のnginxへアクセスできます。

curl コマンドを用いて、レスポンスを確認します。

$ curl http://localhost:8080/
hello from docker on wsl!!<br>
app    | 172.22.0.3 -  09/Aug/2021:10:07:27 +0000 "GET /index.php" 200
web    | 172.22.0.1 - - [09/Aug/2021:10:07:27 +0000] "GET / HTTP/1.1" 200 43 "-" "curl/7.68.0"

index.php でechoした文字列「hello from docker on wsl!!」が表示されています。

また、web コンテナ、app コンテナそれぞれがメッセージを出してきました。

このような表示になれば、うまく設定できています。

index.php の内容を変更・保存し、再度curl コマンドを実行すると、表示内容が変わります。

Windows ホストのブラウザからコンテナにアクセス

最後に、Windows上のブラウザからコンテナにアクセスしてみます。

以前はWindows ホストからWSLにアクセスするには設定が必要だったのですが、今ではとくに何もしなくてもよいようです。

ブラウザを開き、localhost:8080にアクセスしてみます。

あっさり接続できてしまいました。

WSLのDockerで、こんなに簡単にPHP開発環境が作れるとは驚きです。

Docker コンテナを終了する

一通り動作確認をしたら、Docker コンテナを終了します。

$ sudo docker-compose down
Stopping web ...
Stopping app ...
web    | 2021/08/09 10:45:04 [notice] 1#1: signal 3 (SIGQUIT) received, shutting down
web    | 2021/08/09 10:45:04 [notice] 33#33: gracefully shutting down
web    | 2021/08/09 10:45:04 [notice] 34#34: gracefully shutting down

... 中略 ...

Removing web ... done
Removing app ... done
Removing network sample_docker-compose_default
[1]+  Done                    sudo docker-compose up

またコンテナにアクセスしたい場合は、 docker-compose up を実行してください。

まとめ:WSLでも、スムーズにPHP開発環境が構築できるようになりました

今回はこれで終了です。

2021年8月時点では、とても簡単にWSLを使ったPHP開発環境が構築できるようになっていました。感動。

Docker Compose を使いたかったので長くなってしまいましたが、Windows ホストからWSL 上のDocker コンテナにつなげるだけだったら、もっと簡単にできそうです。

PHP のほかにも、node.js やPython の環境も、同じ要領で構築できそうです。

ここから先はDocker の領域に入っていきますので、Docker に関する情報などをあたってみるとよいかと思います。

以上、あなたのお役に立てれば幸いです。

Windows 11 のWSL2(Ubuntu 20.04)にDocker Composeをインストールする

こんにちは、ウチイダです。

前回のDocker インストールに引き続き、Windows 11のWSL2にDocker Composeをインストールして、開発環境を分割しやすくしていきます。

WSL2 のUbuntu上に、Docker がインストールされている前提で手順を見ていきます。

なお、動作環境は以下の通りです。

  • Windwos 11 Pro (21H2 ビルド 22000.120)
  • WSL カーネル バージョン: 5.10.16
  • Windows Terminal バージョン: 1.9.1942.0

GitHub リポジトリから、Docker Composeの最新版をインストール

Docker Composeは、aptなどのパッケージ管理ツールからインストールできないようです。

公式サイトの記載に従って、最新版のリリースをcurlで取得します。

https://github.com/docker/compose/releases

2021年8月時点の最新版は、1.29.2 です。

## GitHubでの最新リリースのバージョン番号を指定してバイナリを取得
$ sudo curl -L https://github.com/docker/compose/releases/download/1.29.2/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose

## ダウンロードしたバイナリに、実行権限を付与
$ sudo chmod +x /usr/local/bin/docker-compose

## バージョン情報を表示して、インストールされたかを確認する
$ docker-compose --version
docker-compose version 1.29.2, build 5becea4c

Docker Composeのコマンド補完をインストール

続いて、公式サイトにオプションとして記載されているコマンド補完機能を導入します。

docker-compose と入力した後にTab キーを押すと、利用できるサブコマンドが表示されたりと、非常に快適になります。

## コマンドライン補完のスクリプトをインストール
$ curl -L https://raw.githubusercontent.com/docker/compose/$(docker-compose version --short)/contrib/completion/bash/docker-compose > /etc/bash_completion.d/docker-compose

## ウチイダの場合、直接 /etc/bash_completion.d/ にファイルを置こうとするとうまくいかなかったので、以下のコマンドで行いました
$ curl -L https://raw.githubusercontent.com/docker/compose/$(docker-compose version --short)/contrib/completion/bash/docker-compose > ~/docker-compose
$ chmod 0644 ~/docker-compose
$ sudo root:root ~/docker-compose
$ sudo mv ~/docker-compose /etc/bash_completion.d

## シェルを再読み込み
$ exec $SHELL -l

## docker-compose のコマンド補完が動作することを確認
$ docker-compose [Tab キーを2回押す]
build    create   events   help     kill     pause    ps       push     rm       scale    stop     unpause  version
config   down     exec     images   logs     port     pull     restart  run      start    top      up

以上で、インストール作業は完了です。

次回はWeb開発のための環境を、Docker Compose で動かしてみることにします。

以上、あなたのお役に立てればうれしいです。

Windows 11 のWSL2(Ubuntu 20.04)にDockerをインストールする

こんにちは、ウチイダです。

前回の記事で、Windows TerminalからWSLを使いやすくする設定を行いました

Windows Terminal起動時にWSLが開くようにする設定と、カラープロファイルを設定しただけですが。。。

ですがこれだけの設定で、WSLを使いたくなったらWindows キーでスタートメニューを開いて、「wt」と入力した後エンターを押すだけで、視認性の高いUbuntuのターミナルが表示できるようになりました。

前回の記事はこちら。

さて今回は、WSL2 のUbuntu にDocker をインストールしていきます。

前提となる動作環境は以下の通りです。

  • Windwos 11 Pro (21H2 ビルド 22000.120)
  • WSL カーネル バージョン: 5.10.16
  • Windows Terminal バージョン: 1.9.1942.0

Docker 公式ドキュメントによると、リポジトリからインストールするのがおすすめの方法ということです。

https://docs.docker.com/engine/install/ubuntu/#install-using-the-repository

上記のページの手順に沿って、作業を進めていきます。

インストール前の準備

とりあえず、パッケージをアップデートして最新の状態にしましょう。

$ sudo apt-get update
$ sudo apt-get upgrade

続いて、リポジトリをHTTPS経由で利用できるようにするためのパッケージをインストールします。

$ sudo apt-get install \
  apt-transport-https \
  ca-certificates \
  curl \
  gnupg \
  lsb-release

Docker のリポジトリを利用するために、GPG鍵を追加します。

正直、この辺よくわかっていません。。。セキュリティのための必要事項だ、くらいの雑な理解をしています。

$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg

前準備の最後の手順です。Docker リポジトリ(安定版、Stable)を追加します。

$ echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

Dockerのインストールと動作確認

追加したリポジトリから、Docker エンジンをインストールします。

$ sudo apt-get update
$ sudo apt-get install docker-ce docker-ce-cli containerd.io

インストールできたか確認してみます。

$ docker --version
Docker version 20.10.8, build 3967b7d

バージョン情報が表示されれば、パッケージのインストールは成功です。

docker コマンドを実行する前に、Docker デーモンを起動しておきます。

$ sudo service docker start
 * Starting Docker: docker

## 起動確認
$ sudo service docker status
 * Docker is running

ちなみに、サービスを起動し忘れてDockerコマンドを実行すると、以下のようなエラーが出ます。

docker: Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?.

Docker デーモンが起動できたら、ようやく動作確認です。hello-world コンテナを動かしてみます。

$ sudo docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
b8dfde127a29: Pull complete
Digest: sha256:df5f5184104426b65967e016ff2ac0bfcd44ad7899ca3bbcf8e44e4461491a9e
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/

## 本当に実行できたのか、コンテナを確認します
$ sudo docker ps -a
CONTAINER ID   IMAGE         COMMAND    CREATED          STATUS                      PORTS     NAMES
f370ebbed892   hello-world   "/hello"   10 seconds ago   Exited (0) 24 seconds ago             goofy_gates

WSL上で、dockerコンテナを動かすことができました!

現在の状態では手動でDocker デーモンを起動する必要があり、最初に動かすときに手間がかかります。

WSLはSystemd が動いていないため、サービスの自動起動などができなくて不便ですね。

このあたりの解決方法はまた別の機会に。

今回の内容は以上です。

あなたのお役に立てればうれしいです。

docker-composeからDockerfileへ変数を渡す

docker-compose.ymlで管理するサービスのイメージを自分でビルドするときに、Dockerfileへ変数を渡すのに苦労したのでメモしておきます。

ymlを書き換えるのではなくて、.envを書き換えるだけで済むようにしたかったのです。

コマンド入力するときにオプションで渡すのも面倒だったし…

最終的に、以下のようにしたらできました。

  • .envファイルに変数名=値 の形式で列挙
  • さらに、args に変数を列挙して、Dockerfileに変数を届ける
  • Dockerfile側で、ARGS で変数の利用を宣言する

動作テストのため、以下のdocker-compose.ymlとDockerfikeを作成しました。

まずはdocker-compose.ymlから。

version: "3.9"

services:
  env_test:
    container_name: "env_test"
    build:
      context: "./build"
      dockerfile: "Dockerfile"
      args: # .env で宣言している変数を、イメージビルド時に使えるようにします
       - ENV_FROM_COMPOSE=$ENV_FROM_COMPOSE

つづいて、Dockerfileです。

FROM alpine:latest
ARG ENV_FROM_COMPOSE

RUN echo "env value: ${ENV_FROM_COMPOSE}"

CMD ["/bin/bash"]

.envには変数を設定。

ENV_FROM_COMPOSE=hello_from_docker-image-building!!

ビルドしてみます。

$ docker-compose build
Building env_test
[+] Building 0.5s (6/6) FINISHED
 => [internal] load build definition from Dockerfile                                                                                                                           0.0s
 => => transferring dockerfile: 37B                                                                                                                                            0.0s
 => [internal] load .dockerignore                                                                                                                                              0.0s
 => => transferring context: 2B                                                                                                                                                0.0s
 => [internal] load metadata for docker.io/library/alpine:latest                                                                                                               0.0s
 => CACHED [1/2] FROM docker.io/library/alpine:latest                                                                                                                          0.0s
 => [2/2] RUN echo "env value: hello_from_docker-image-building!!"                                                                                                             0.3s
 => exporting to image                                                                                                                                                         0.0s
 => => exporting layers                                                                                                                                                        0.0s
 => => writing image sha256:fc3c6c7aff6c5670a461dd324a2c81b2029389e5e1f0145110e6b50dbbd1b956                                                                                   0.0s
 => => naming to docker.io/library/docker-env-test_env_test

ステージ [2/2]で、データが$ENV_FROM_COMPOSE が展開されて、値が表示されています。

ビルドステージでechoしても、こちらには表示されませんけど…

ビルド時にdocker-composeから値を渡したいときは、この記述方法が使えそうです。

注意点:docker-compose.yml のenv_fileは動作が違う!

2021.08.12 追記です。

docker-compose.ymlには、「env_file」という要素もあります。

これは、docker-compose 経由で立ち上げられたコンテナの中で利用できる環境変数を、外部ファイルに列挙しておくためのものです。

ここでファイルを指定しても、docker-compose.ymlの中で利用することはできません。

たとえば、「.another_env」というファイルを作って環境変数を列挙しておき、docker-compose.ymlにenv_fileで指定しても、.another_envに書かれた変数はdocker-compose.ymlからは利用できませんが、ビルドしたコンテナ内では利用できます。

version: "3.9"

services:
  env_test:
    container_name: "env_test"
    env_file:
      # .another_envに記載された変数は、docker-compose.ymlの中では利用できない!!
      - ./.another_env
    build:
      context: "./build"
      dockerfile: "Dockerfile"

.env 以外のファイルを読み込んでdocker-compose.yml内で利用する方法は、ちょっと調べただけではわかりませんでした。後日、また調査しておきます。。。

以上です。あなたのお役に立てればうれしいです。

別サーバのMariaDBに接続すると、ERROR 2002が発生する

MariaDBを動かしているDockerコンテナに別のコンテナから接続をしたら、以下のエラーが発生しました。

root@a90917286208:/# mysql -h mariadb                        
ERROR 2002 (HY000): Can't connect to MySQL server on 'mariadb' (115)

MariaDBの設定項目にはbind-addressというものがあり、指定した接続元のみアクセスを許可することができるようです。

初期設定では、127.0.0.1 からの接続のみが許可されています。

ウチイダのコンテナでは、/etc/mysql/mariadb.conf.d/50-server.cnf に設定がありました。

#
# These groups are read by MariaDB server.
# Use it for options that only the server (but not clients) should see
#
# See the examples of server my.cnf files in /usr/share/mysql

# this is read by the standalone daemon and embedded servers
[server]

# this is only for the mysqld standalone daemon
[mysqld]

#
# * Basic Settings
#
user                    = mysql
pid-file                = /run/mysqld/mysqld.pid
socket                  = /run/mysqld/mysqld.sock
#port                   = 3306
basedir                 = /usr
datadir                 = /var/lib/mysql
tmpdir                  = /tmp
lc-messages-dir         = /usr/share/mysql
#skip-external-locking

# Instead of skip-networking the default is now to listen only on
# localhost which is more compatible and is not less secure.
#  bind-address            = 127.0.0.1 # <- 初期設定されているので、コメントアウト

~ (以下略) ~

設定を変更して、Mariadb を再起動します。

再度、接続しなおしてみます。

root@a90917286208:/# mysql -h mariadb
ERROR 1698 (28000): Access denied for user 'root'@'app'

エラー内容が ERROR 1698 に変わりました。

MariaDBのcliは、指定しないとrootユーザーで接続を試みます。

初期設定ではrootはlocalhostからのみ接続を許可するので、権限がないためエラーになっています。

MariaDBのuser テーブルに、外部ホストからの接続を許可するユーザーを作成します。

CREATE USER 'app-user'@'app' IDENTIFIED BY 'app-user-password';
GRANT ALL PRIVILEGES ON appdb.* TO 'app-user'@'app' WITH GRANT OPTION;

新たに作成し他ユーザーを指定して接続してみます。

root@a90917286208:/# mysql -h mariadb -u appuser -p 
Enter password: 
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 9
Server version: 10.3.29-MariaDB-0+deb10u1 Debian 10

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MariaDB [(none)]> 

MariaDBに、外部から接続することができました。

Dockerを利用する場合、MySQL のイメージを使えば最初から良い感じに設定してくれているようなので、通常はあまりつまづくことのない問題かと思いますが…

以上です。あなたのお役に立てればうれしいです。

Dockerfileの上位ディレクトリにあるファイルをCOPYする

基本的に、Dockerfileは親ディレクトリにあるファイルを参照することができません。

サンプルとして、以下のようなディレクトリ構造でDockerfileからビルドしてみます。

$ /tmp/copy_test$ tree ./
./
├── dir_in_Dockerfile
│   ├── Dockerfile
│   ├── child_dir
│   │   └── testfile_in_childdir.txt
│   └── testfile.txt
└── testfile_in_parent.txt

2 directories, 4 files

テスト用のDockerfileはこのように作成しました。

FROM alpine:latest

COPY ./testfile.txt /tmp

# 親ディレクトリのファイル
COPY ../testfile_in_parent.txt /tmp

# 子ディレクトリのファイル
COPY ./child_dir/testfile_in_child.txt /tmp 

# 絶対パスでの記述
COPY /tmp/testfile_in_tmp.txt /tmp 

CMD ["/bin/sh"]

dir_in_Dockerfile でビルドをしてみます。

/tmp/copy_test/dir_in_Dockerfile$ docker build .
[+] Building 0.1s (9/9) FINISHED
 => [internal] load build definition from Dockerfile
 => => transferring dockerfile: 38B
 => [internal] load .dockerignore
 => => transferring context: 2B
 => [internal] load metadata for docker.io/library/alpine:latest
 => CACHED [1/5] FROM docker.io/library/alpine:latest
 => [internal] load build context
 => => transferring context: 112B
 => CACHED [2/5] COPY ./testfile.txt /tmp
 => ERROR [3/5] COPY ../testfile_in_parent.txt /tmp
 => CACHED [4/5] COPY ./child_dir/testfile_in_child.txt /tmp
 => ERROR [5/5] COPY /tmp/testfile_in_tmp.txt /tmp

親ディレクトリのファイルを指定した部分([3/5] COPY ../testfile_in_parent.txt /tmp)と、絶対パスでファイルを指定した部分(ERROR [5/5] COPY /tmp/testfile_in_tmp.txt /tmp)でエラーが起きています。

どうしてもDockerfileの親階層のファイルを参照したいとき

Dockerfileの上位ディレクトリにあるファイルをCOPYしたい場合、ビルドコンテクストを指定する必要があります。

以下のように、Dockerfileを書き換えます。

# docker buildコマンドで、Dockerfileの親ディレクトリをコンテキストに指定してビルド実行する

FROM alpine:latest

# Dockerfileと同階層のファイル
COPY ./dir_in_Dockerfile/testfile.txt /tmp

# Dockerfileからみて親ディレクトリにあるファイルを、カレントディレクトリとして参照
COPY ./testfile_in_parent.txt /tmp

# 子ディレクトリのファイル
COPY ./dir_in_Dockerfile/child_dir/testfile_in_child.txt /tmp 

# 絶対パスでの記述
COPY /tmp/testfile_in_tmp.txt /tmp 

CMD ["/bin/sh"]

そして、 docker build する際に-f オプションでDockerfileの位置と、コンテキスト(基準になるディレクトリ)を指定します。

/tmp/copy_test/dir_in_Dockerfile$ docker build -f ./Dockerfile ../
[+] Building 0.2s (9/9) FINISHED
 => [internal] load build definition from Dockerfile
 => => transferring dockerfile: 38B
 => [internal] load .dockerignore  
 => => transferring context: 2B    
 => [internal] load metadata for docker.io/library/alpine:latest
 => [internal] load build context                               
 => => transferring context: 242B                               
 => CACHED [1/5] FROM docker.io/library/alpine:latest           
 => CACHED [2/5] COPY ./dir_in_Dockerfile/testfile.txt /tmp     
 => CACHED [3/5] COPY ./testfile_in_parent.txt /tmp             
 => CACHED [4/5] COPY ./dir_in_Dockerfile/child_dir/testfile_in_child.txt /tmp
 => ERROR [5/5] COPY /tmp/testfile_in_tmp.txt /tmp                            
------
 > [5/5] COPY /tmp/testfile_in_tmp.txt /tmp:
------
failed to compute cache key: "/tmp/testfile_in_tmp.txt" not found: not found

今度は、絶対パスで指定した部分(ERROR [5/5] COPY /tmp/testfile_in_tmp.txt /tmp)だけがエラーになりました。

コンテキストはデフォルトではDockerfileのある階層になるため、そのままだと親階層のファイルが使えません。

明示的に親ディレクトリを指定することで、Dockerfileの親階層のファイルも参照できます。

一応この方法で実現できますが、Dockerfikeに記載されたパスと実際に参照されるファイルの所在が変わってしまううえ、Dockerfile上のすべてのパスを書き換える必要があります。

加えて、ビルドの際に適切にオプションと引数を指定しないと意図した内容がビルドされません。

しかも、、、コンテキストに指定されたディレクトリ以下にあるファイルは、すべてDockerデーモンに送信されてしまい、ビルドに時間がかかる原因にもなったりするみたいです。

あくまで「一応できる」というものであり、副作用が多いですね。あまり多用しない方がよさそうです。

以上です。あなたのお役に立てればうれしいです。

docker-compose でホスト側の任意のディレクトリをマウントできない

動作環境

  • Windows 10 Pro
  • WSL2 ubuntu
  • Docker Desktop for Windows

dockerが自動で作ってくれるディレクトリではなく、ホスト側で任意に作成したディレクトリをマウントさせたいという状況がありました。

調べてみたところ、トップレベルでvolumesを定義するとよいみたいです。

しかし、いろんなところに書いてあるやり方でymlを記述してもエラーがでます。。。

version: "3.9"

services:
  mount_test:
    container_name: "mount_test"
      image: alpine
      tty: true
      volumes:
        - volume_test:/tmp/mounted_from_host

volumes:
  volume_test:
   driver_opts:
     type: none
     device: /var/docker_test/volume # このディレクトリはあらかじめ作成されており、いくつかのファイルが入っている
     o: bind

エラーの内容は以下のような感じ。

$ docker-compose up -d
Creating network "docker-compose-test_mount_from_host_default" with the default driver
Creating volume "docker-compose-test_mount_from_host_volume_test" with default driver
Creating mount_test ... error

ERROR: for mount_test  Cannot start service mount_test: error while mounting volume '/var/lib/docker/volumes/docker-compose-test_mount_from_host_volume_test/_data': failed to mount local volume: mount /var/docker_test/volume:/var/lib/docker/volumes/docker-compose-test_mount_from_host_volume_test/_data, flags: 0x1000: no such file or directory

ERROR: for mount_test  Cannot start service mount_test: error while mounting volume '/var/lib/docker/volumes/docker-compose-test_mount_from_host_volume_test/_data': failed to mount local volume: mount /var/docker_test/volume:/var/lib/docker/volumes/docker-compose-test_mount_from_host_volume_test/_data, flags: 0x1000: no such file or directory
ERROR: Encountered errors while bringing up the project.

なぜかdockerが自動生成したディレクトリにマウントしようとしています。

修正:ボリュームの定義にdriverを追加する

「driver: local」と追加しました。この項目が必要なようです。いつからか仕様が変わったんですかね…

version: "3.9"

services:
  mount_test:
    container_name: "mount_test"
      image: alpine
      tty: true
      volumes:
        - volume_test:/tmp/mounted_from_host

volumes:
  volume_test:
   driver: local # ここを追加
   driver_opts:
     type: none
     device: /var/docker_test/volume
     o: bind

修正したymlで再度試したら、ちゃんとできました。

実行前に、前回のエラーで作成されたネットワークとボリュームを片付けておきます。

$ docker-compose down && docker volume rm docker-compose-test_mount_from_host_volume_test
Removing mount_test ... done
Removing network docker-compose-test_mount_from_host_default
docker-compose-test_mount_from_host_volume_test
$
$ docker-compose up -d
Creating network "docker-compose-test_mount_from_host_default" with the default driver
Creating volume "docker-compose-test_mount_from_host_volume_test" with local driver
Creating mount_test ... done
$
$ docker-compose exec mount_test cat /tmp/mounted_from_host/helloworld.txt
hello world from mounted from host!!

以上、あなたのお役に立てれば幸いです。