Linux インストール後の作業

読む時間の目安: 7 分

ここに示すのは任意の作業ですが、Linux ホストにおいて Docker をよりよく動作させるための設定を行います。

root ユーザー以外で Docker を管理する

Docker デーモンは TCP ポートのかわりに Unix ソケットにバインドされます。 デフォルトで Unix ソケットの所有者はrootユーザーであるため、他のユーザーはsudoを使ってアクセスすることになります。 Docker デーモンは常にrootユーザーが起動しています。

dockerコマンドの実行にあたってsudoを用いたくない場合は、dockerという Unix グループを生成してユーザーをそのグループに加えます。 Docker デーモンが起動したときに生成される Unix ソケットは、dockerグループに所属するユーザーであればアクセスすることが可能です。

注意

dockerグループはrootユーザーと同等の権限を持ちます。 このことがシステムセキュリティ上でどのような意味を持つのか、Docker Daemon Attack Surface を参照してください。

メモ:

ルート権限なしに Docker をインストールする場合は 非ルートユーザーとして Docker デーモンを起動する (rootless モード) を参照してください。

rootless モードは現時点では、試験的機能として利用できます。

dockerグループを生成してユーザーを追加します。

  1. dockerグループを生成します。

    $ sudo groupadd docker
    
  2. ユーザーをdockerグループに追加します。

    $ sudo usermod -aG docker $USER
    
  3. いったんログアウトしてからログインし直してください。 グループに属することが認識されるようにするためです。

    仮想マシン上でテストを行っている場合は、仮想マシンを再起動して設定を有効にする必要が出てくるかもしれません。

    X ウィンドウのような Linux デスクトップ環境においては、いったんセッションから完全にログアウトして、再ログインを行ってください。

    Linux ではまた、以下のコマンドによってグループ変更を行うこともできます。

    $ newgrp docker
    
  4. sudoがなくてもdockerコマンドが実行できることを確認します。

    $ docker run hello-world
    

    このコマンドはテストイメージをダウンロードして、コンテナー内で実行します。 コンテナーが起動すると、メッセージを表示して終了します。

    dockerグループへのユーザー追加を行わずにsudoを使って Docker CLI コマンドを実行していたときは、以下のエラーが出ていたかも知れません。 これはsudoコマンドを使っているために、~/.docker/ディレクトリが不適切なパーミッションにより生成されたことを示しています。

    WARNING: Error loading config file: /home/user/.docker/config.json -
    stat /home/user/.docker/config.json: permission denied
    

    この問題を解消するには、1 つには~/.docker/ディレクトリをいったん削除することです。 (このディレクトリは自動的に再作成されます。ただし追加設定している内容は失われます。) あるいは以下のコマンドのようにして、所有者とパーミッションを変更することです。

    $ sudo chown "$USER":"$USER" /home/"$USER"/.docker -R
    $ sudo chmod g+rwx "$HOME/.docker" -R
    

システムブート時の Docker 起動設定

最近の Linux ディストリビューション(RHEL、CentOS、Fedora、Debian、Ubuntu 16.04 およびそれ以上)の多くでは、systemd を使ってシステムブート時のサービス起動の管理を行っています。 Debian や Ubuntu では、デフォルトで Docker サービスがシステムブート時に起動するように設定されています。 他のディストリビューションにおいて Docker や Containerd をブート起動するには、以下のコマンドを用います。

$ sudo systemctl enable docker.service
$ sudo systemctl enable containerd.service

無効にするには、かわりにdisableを用います。

$ sudo systemctl disable docker.service
$ sudo systemctl disable containerd.service

HTTP プロキシーを加える必要がある場合、Docker の起動に関連するファイルは別のディレクトリ、あるいは別のパーティションに置きます。 あるいは別の設定を行うこともあります。 詳しくは systemd での Docker デーモンオプションの設定 を参照してください。

異なるストレージドライバーの利用

さまざまなストレージエンジンに関する情報は、ストレージドライバー を参照してください。 デフォルトのストレージエンジン、あるいはサポートされるストレージエンジンは何かということは、利用する Linux ディストリビューションおよび利用可能なカーネルドライバーによります。

デフォルトのログドライバーの設定

Docker では ログドライバーの機能 を通じて、ホスト上に稼動するすべてのコンテナーからログを収集して参照する機能が提供されています。 デフォルトのログドライバーはjson-fileであり、ホスト上のファイルシステム内に JSON 形式のファイルとしてログデータを保存します。 時間の経過とともにログファイルはサイズが増大するため、気づかないうちにディスクリソースを浪費することにつながります。

この問題を解消するためには、json-fileログドライバーにおいて ログローテーション を有効にしたり、「local」ログドライバー などのようにログローテーションをデフォルトで対応している 別のログドライバー を用いるようにします。 あるいはリモートのログ収集サイトにログ出力を行うログドライバーは利用します。

Docker デーモンがどこからの接続待ちをするかの設定

デフォルトにおいて Docker デーモンは、UNIX ソケットにより接続を待ち(リッスンし)、ローカルクライアントからの要求を受け付けます。 リモートホストから要求は UNIX ソケットからだけでなく、設定により IP アドレスおよびポートから受け付けるようにすることも可能です。 そのような設定オプションについての詳細は、Docker CLI リファレンス のセクション「Bind Docker to another host/port or a unix socket」を参照してください。

セキュアな接続

Docker においてリモートホストからの接続を許可する設定を行うには、十分に理解しておくべきことがあります。 ネットワークに向けて Docker をオープンなものにするということは、セキュリティに関する問題を大いに含んでいるということです。 設定を誤ってセキュアな接続が確保されていなかったら、それはつまり、リモートの root ユーザー以外がホスト上の root 権限を奪取してしまいます。 TLS 証明書を使ってセキュアな接続を行う方法については、Docker デーモンソケットを守る方法 の説明を参照してください。

リモート接続を許可する設定は systemd ユニットファイルdocker.serviceを使って行うことができます。 これは systemd を利用する Linux ディストリビューション、たとえば RedHat、CentOS、Ubuntu、SLES の最新版において設定できます。 あるいはdaemon.jsonファイルを使う方法もあります。 systemd を利用していない Linux ディストリビューションでは、この方法が推奨されます。

systemd 対 daemon.json

Docker が接続待ちを行う設定としてsystemdユニットファイルとdaemon.jsonの双方を利用してしまうと、両者が衝突し Docker が起動しなくなりますから注意してください。

systemdユニットファイルによるリモートアクセスの設定

  1. sudo systemctl edit docker.serviceとコマンド入力し、docker.serviceに対してオーバーライドするファイルをテキストエディターで開きます。

  2. 以下の行を追加、修正します。 各値はそれぞれの環境に合わせたものに置き換えます。

    [Service]
    ExecStart=
    ExecStart=/usr/bin/dockerd -H fd:// -H tcp://127.0.0.1:2375
    
  3. ファイルを保存します。

  4. systemctlの設定を再読み込みします。

     $ sudo systemctl daemon-reload
    
  5. Docker を再起動します。

    $ sudo systemctl restart docker.service
    
  6. 設定の変更が適用されたことを確認するためnetstatの出力を見ます。 dockerdが指定したポートで接続待ちしていることを確認します。

    $ sudo netstat -lntp | grep dockerd
    tcp        0      0 127.0.0.1:2375          0.0.0.0:*               LISTEN      3758/dockerd
    

daemon.jsonによるリモートアクセスの設定

  1. /etc/docker/daemon.json内のhostsに配列として、UNIX ソケットと IP アドレスを以下のように設定します。

    {
      "hosts": ["unix:///var/run/docker.sock", "tcp://127.0.0.1:2375"]
    }
    
  2. Docker を再起動します。

  3. 設定の変更が適用されたことを確認するためnetstatの出力を見ます。 dockerdが指定したポートで接続待ちしていることを確認します。

    $ sudo netstat -lntp | grep dockerd
    tcp        0      0 127.0.0.1:2375          0.0.0.0:*               LISTEN      3758/dockerd
    

Docker デーモンの IPv6 利用

Docker デーモンに対して IPv6 を有効にするには、IPv6 サポートの有効化 を参照してください。

トラブルシューティング

カーネルの条件

Docker は Linux カーネルが 3.10 より古い場合、あるいは所定のモジュールがない場合には正常に起動しません。 カーネルが適合していることをチェックするには、check-config.sh スクリプトをダウンロードして実行する方法があります。

$ curl https://raw.githubusercontent.com/docker/docker/master/contrib/check-config.sh > check-config.sh

$ bash ./check-config.sh

このスクリプトは Linux 上でのみ動作します。 macOS では動作しません。

Cannot connect to the Docker daemon

以下に示すようなエラーが発生した場合は、Docker クライアントから Docker デーモンへ接続する設定が、間違ったホストになっている可能性があります。そしてそのホストへはネットワークが届いていません。

Cannot connect to the Docker daemon. Is 'docker daemon' running on this host?

クライアントがどのホストに接続しにいくように設定されているのかは、環境内にてDOCKER_HOST変数を確認することで分かります。

$ env | grep DOCKER_HOST

Docker デーモンに対して Docker クライアントが接続するホストは、上のコマンドの戻り値であるホストとなります。 変数が未設定の場合、Docker クライアントはローカルホストで稼動する Docker デーモンに接続しにいきます。 設定に誤りがある場合は、以下のコマンドにより変数を未設定とします。

$ unset DOCKER_HOST

DOCKER_HOSTを適切に設定するためには、~/.bashrc~/.profileといったファイルを用いて環境設定をしておくことが必要かもしません。

DOCKER_HOSTを正しく設定したら、Docker デーモンがリモートホスト上に稼動していて、ファイアウォールやネットワークには問題がなく、接続ができることを確認します。

IP フォワーディングに関する問題

systemdバージョン 219 またはそれ以上を用いている場合で、systemd-networkを使ってネットワークを手動で設定している場合、Docker コンテナーがネットワーク上でアクセスできないかもしれません。 systemdバージョン 220 以降、指定されたネットワークのフォワーディング設定(net.ipv4.conf.<interface>.forwarding)がデフォルトでオフとなりました。 この設定では IP フォワーディングが行われません。 またコンテナー内にてnet.ipv4.conf.all.forwardingを有効にすることは、Docker の動作と衝突を起こします。

RHEL、CentOS、Fedora においてこれを回避するには、Docker ホスト内の/usr/lib/systemd/network/にある<interface>.networkファイル(たとえば /usr/lib/systemd/network/80-container-host0.network)を編集します。 [Network]セクション内に以下の記述を加えます。

[Network]
...
IPForward=kernel
# または
IPForward=true
...

この設定によって、コンテナー内からの IP フォワーディングが正常に行われるようになります。

DNS resolver found in resolv.conf and containers can't use it

GUI を利用している Linux システムでは、ネットワークマネージャーを起動していることがよくあります。 そのときにはdnsmasqインスタンスをループバックアドレス、たとえば127.0.0.1127.0.1.1などにおいて稼動させて DNS リクエストをキャッシュしています。 この情報は/etc/resolv.confに項目追加されています。 dnsmasqサービスは DNS の問い合わせ処理を高速にし、また DHCP サービスも提供するものです。 Docker コンテナーは独自のネットワーク名前空間を持つため、その設定はコンテナー内では動作しません。 というのも、Docker コンテナーは127.0.0.1などのループバックアドレスを自分そのものと解釈するためです。 したがって独自のループバックアドレスのもとで DNS サーバーを稼動させることが、まずできません。

/etc/resolv.conf内に設定されている DNS サーバーが十分に機能していないことが Docker によって検出されると、以下の警告メッセージが出力され、Docker は Google によって提供されている公開の DNS サーバー、つまり8.8.8.88.8.4.4を使って DNS 名前解決を行います。

WARNING: Local (127.0.0.1) DNS resolver found in resolv.conf and containers
can't use it. Using default external servers : [8.8.8.8 8.8.4.4]

この警告メッセージが出力された場合は、まず最初にdnsmasqが利用されているかどうかを確認します。

$ ps aux |grep dnsmasq

ネットワーク内部にあるホストの名前解決をコンテナーがしなければならないのであれば、公開のネームサーバーを用いるのは不適当です。以下の 2 つの選択を行ってください。

  • Docker が利用する DNS サーバーを指定してください。あるいは
  • ネットワークマネージャーによるdnsmasqの利用を停止してください。 これを行った場合、ネットワークマネージャーは/etc/resolv.confに本当の DNS ネームサーバーを追加します。ただしdnsmasqによる機能性は失われます。

上の 2 つのうち 1 つだけを選んで実行してください。

Docker が利用する DNS サーバーの指定

設定ファイルがあるのはデフォルトでは/etc/docker/daemon.jsonです。 この設定ファイルの場所を変更するには、デーモンフラグ--config-fileを使います。 以降において、設定ファイルは/etc/docker/daemon.jsonにあるものとして説明していきます。

  1. デフォルトで/etc/docker/daemon.jsonとなっている Docker デーモンの設定ファイルを生成編集します。 このファイルが Docker デーモンの設定を制御します。

    $ sudo nano /etc/docker/daemon.json
    
  2. dnsキーを追加して、その値に 1 つあるいは複数の IP アドレスを設定します。 このファイルにすでに内容が書き込まれている場合は、dnsの行だけを追加します。

    {
      "dns": ["8.8.8.8", "8.8.4.4"]
    }
    

    ネットワーク内の DNS サーバーが、パブリック IP アドレスの名前解決ができなかったとしても、少なくともそれができる DNS サーバーをここに加えることになります。 こうすれば Docker Hub にもアクセスでき、コンテナーがインターネットドメイン名を解決できることになります。

    ファイルを保存して閉じます。

  3. Docker デーモンを再起動します。

    $ sudo service docker restart
    
  4. Docker が外部の IP アドレスを解決できるかどうかを確認するために、イメージを取得してみます。

    $ docker pull hello-world
    
  5. 必要なら Docker コンテナーが、内部ホスト名も解決できることを確認するため ping を行ってみます。

    $ docker run --rm -it alpine ping -c4 <my_internal_host>
    
    PING google.com (192.168.1.2): 56 data bytes
    64 bytes from 192.168.1.2: seq=0 ttl=41 time=7.597 ms
    64 bytes from 192.168.1.2: seq=1 ttl=41 time=7.635 ms
    64 bytes from 192.168.1.2: seq=2 ttl=41 time=7.660 ms
    64 bytes from 192.168.1.2: seq=3 ttl=41 time=7.677 ms
    

dnsmasqの無効化

Ubuntu

Docker デーモンが特定の IP アドレスを利用するような設定を行いたくない場合は、以下の手順に従って、ネットワークマネージャーのdnsmasqを無効にします。

  1. /etc/NetworkManager/NetworkManager.confファイルを編集します。

  2. dns=dnsmasqの行をコメントアウトするため、行の先頭に#を書き加えます。

    # dns=dnsmasq
    

    ファイルを保存して閉じます。

  3. ネットワークマネージャーと Docker をともに再起動します。 あるいはシステムをリブートします。

    $ sudo restart network-manager
    $ sudo restart docker
    
RHEL、CentOS、Fedora

RHEL、CentOS、Fedora においてdnsmasqを無効にするには以下のようにします。

  1. dnsmasqサービスを無効にします。

    $ sudo service dnsmasq stop
    
    $ sudo systemctl disable dnsmasq
    
  2. Red Hat ドキュメントを参考にして、DNS サーバーを手動で設定します。

ファイアーウォール越しにリモート API へのアクセスを許可する

Docker を起動させているホストにおいてファイアーウォールを設定している場合に、他のホストからの Docker リモート API へアクセスしたり、リモートホストへのアクセスを可能にしたりしたいときは、ファイアウォールの設定が必要であり、Docker ポートを通る内部への接続を有効にします。 TLS 暗号化転送が有効な場合は、デフォルトの2376、そうでない場合は2375です。

代表的なファイアーウォールデーモンといえば、UFW (Uncomplicated Firewall)(Ubuntu において利用されることが多い)と firewalld(RPMベースのシステムで利用されることが多い)の 2 つがあります。 OS やファイアーウォールに関するドキュメントをよく確認することになりますが、以下の情報も手始めとして参考になるかもしれません。 ただしこの方法ではやや寛容すぎるというので、システムの設定を違った方法で強固にしたいと思うかもしれません。

  • UFW: 設定ファイルにてDEFAULT_FORWARD_POLICY="ACCEPT"を設定します。

  • firewalld: ポリシーに以下のようなルールを追加します。 (1 つは内部接続要求用、もう 1 つは外部接続要求用です。) インターフェース名とチェイン名が正しいことを確認してください。

    <direct>
      [ <rule ipv="ipv6" table="filter" chain="FORWARD_direct" priority="0"> -i zt0 -j ACCEPT </rule> ]
      [ <rule ipv="ipv6" table="filter" chain="FORWARD_direct" priority="0"> -o zt0 -j ACCEPT </rule> ]
    </direct>
    

Your kernel does not support cgroup swap limit capabilities

Ubuntu や Debian の場合、イメージの動作中に以下のようなメッセージが表示されることがあります。

WARNING: Your kernel does not support swap limit capabilities. Limitation discarded.

RPM ベースのシステムではスワップ領域の制限機能(swap limit capability)があるため、このメッセージは発生しません。

この機能が不要であれば、警告メッセージを無視して構いません。 Ubuntu や Debian においてこの機能を有効にするには以下の手順に従います。 メモリとスワップの計算には、メモリ使用総量の 1% のオーバーヘッドが発生します。 また全体として 10% の処理性能ダウンが発生します。 これは Docker を稼動しなくても発生するものです。

  1. sudo権限を持つユーザーを使って Ubuntu あるいは Debian にログインします。

  2. /etc/default/grubファイルを編集します。 GRUB_CMDLINE_LINUXの行を新規追加あるいは編集して、以下の 2 つのキーバリューのペアを追加します。

    GRUB_CMDLINE_LINUX="cgroup_enable=memory swapaccount=1"
    

    ファイルを保存して閉じます。

  3. GRUB をアップデートします。

    $ sudo update-grub
    

    GRUB の設定ファイルに文法誤りがあれば、エラーが発生します。 その場合は手順 2 と 3 を再度行います。

    変更を有効にするために、システムを再起動します。

次のステップ

  • Docker をはじめよう に示すトレーニングを見てください。 イメージのビルド方法や、イメージをコンテナー化アプリケーションとして起動する方法を学んでいきます。
  • Docker を用いた開発 における各項目を参照してください。 Docker を使ったアプリケーションの構築方法を学びます。
Docker, Docker documentation, requirements, apt, installation, ubuntu, install, uninstall, upgrade, update