高速で軽量な仮想環境を構築できるDockerは、その利便性から、ソフトウェアの開発者にとってもシステムの管理者にとっても使い方を知っておくべきソフトウェアとしての地位を確立しつつあります。今回はより新しいDockerをUbuntu上で使う上で、気をつけるべきことをおさらいします。
UbuntuにおけるDocker
2017年7月追記:Dockerのリリースポリシーの変更にあわせて、リポジトリのURLやパッケージ名が変更になりました。本記事は新しい手順に更新済みです。記事中の「docker-engineパッケージ」は「docker-ceパッケージ」と読み替えてください。
Dockerはカーネルのコンテナ技術などを利用して、アプリケーションをサンドボックス環境の中で動かす仕組みです。Dockerでは最小限のルートファイルシステムである「Dockerのベースイメージ」の上に、各種ソフトウェアのインストール手順や設定手順をファイルとして記述した「Dockerfile
」を用いて環境を構築します。Dockefile
さえあれば、機械的に何度でもいろいろなところで同じ環境を再構築できるのです。折しも現在発売中の『Software Design 2017年2月号』の第1特集は「いまはじめるDocker」と題したDocker特集になっていますので、より応用的な使い方を知りたい場合はそちらを参照してください[1]。
さてそのDockerを使うためには、まずDockerエンジンと呼ばれるデーモンとそのDockerエンジンを操作するクライアントをインストールする必要があります[2]。UbuntuにDockerをインストールする方法は、実はいくつか存在します。
- Docker公式のdocker-ce(旧称:docker-engine)パッケージをインストールする方法
- Ubuntu公式リポジトリにあるdocker.ioパッケージをインストールする方法
- snapを使ってdockerパッケージをインストールする方法
最新版を使いたいのであれば、Docker公式のパッケージを使う方法が一番確実です。常に最新のリリースに追随していますし、そのパッケージの作りもUbuntuの流儀から外れてはいません。
最新版にこだわりがないのであれば、公式リポジトリのパッケージをインストールする方法が一番簡単でしょう。なにせ公式リポジトリにパッケージがあるので、インストールはapt
コマンドを実行するだけです。Dockerは昨今のシステムでは必須とも言えるコンポーネントになっているため、LTSへのSRUも積極的に行われています。末尾の「.1」のリリース以降のいずれかのタイミングでUbuntu 16.04 LTSにも導入されますので、2017年2月頭の時点でインストールできるのは「1.12.3」です。また、おそらく近いうちに「1.12.6」に更新される見込みです。よって、常にリリースされたばかりのバージョンが必要という用途でなければ、Ubuntuリポジトリのパッケージも選択肢に入ってくるでしょう。
ちなみにdocker.ioパッケージにはLXD上でDockerを使うためのパッチが当たっています。LXDの上でDockerを使いたいのであれば、Ubuntuのdocker.ioパッケージを使うと良いでしょう。
snap版は、新しいパッケージングシステムである「snap」でパッケージ化されたDockerです。snapではアプリケーションやサービスをすべてAppArmorやseccomp、cgroup、namespaceなどを用いて「ホストから隔離した環境」上で実行する仕組みになっています。現時点でのsnap版のdockerパッケージは、「このような隔離環境でもDockerがきちんと動く」ことを示す技術的デモに近い位置づけですので、現時点でこれを通常のデスクトップやサーバーで使う意味はありません。たとえばIoT向けのUbuntu Coreシステム上で、Dockerを用いたサービスを立ち上げたいといった用途であれば、意味が出てくるでしょう[3]。
Dokcer公式のdocker-engineパッケージ
Docker公式のdocker-engineパッケージについては、Dockerのドキュメントにとても丁寧なインストール手順が記載されています。この手順に従えば何の問題もありません。ここではいくつか細かい注意点を付記しておきましょう。
必要なパッケージのインストール
まず最初に、最低限必要なパッケージをインストールします。
curlはこのあとリポジトリのGPG鍵をダウンロードするために使用します。サーバー版だと最初からインストールされていますが、デスクトップ版だと入っていないかもしれません。apt-transport-httpsとca-certificatesはDockerのリポジトリがHTTPSであるために必要なパッケージです。software-properties-commonはadd-apt-repository
コマンドのためにインストールしています。ただし普通にUbuntuをインストールすれば、いずれのパッケージも最初からインストールされているはずです。
最後の2つのカーネル関連のパッケージは、Storage Driverとしてaufsを使いたいかOverlayFSを使いたい場合に必要となります。Dockerのインストールドキュメントには「(インストールしない)強い理由がないのであればインストールしましょう」と書いてありますので、特に理由がなければインストールしておきましょう。ちなみにデスクトップ版であれば最初からインストールされています。
DockerのStorage Driverは、Dockerイメージを保存するための仕組みです。過去にはaufsが使われていましたが、最近はOverlayFSやDevice Mapperなど複数のStorage Driverをサポートするようになりました。「Select a storage driver」には個々のStorage Driverの特性や選択基準が記載されていますので、必要に応じて確認すると良いでしょう。Ubuntuの場合、上記カーネルパッケージをインストールしているとaufsを使うようになります。
「linux-image-generic」「linux-image-extra-VERSION」そしてDockerのドキュメントにある「linux-image-extra-virtual」の関係についても説明しておきましょう。Ubuntuにおいてカーネル本体とカーネルモジュールは「linux-image-VERSION-generic」パッケージによって提供されます[4]。「linux-image-generic」は「リポジトリにある最新のバージョンのパッケージに依存している」ため、「linux-image-generic」をインストールしておけばパッケージの更新によって常に最新のパッケージがインストールされます。
カーネルモジュールのうち起動時には使わないものは「linux-image-extra-VERSION」に分離してパッケージ化されています。しかしながら「linux-image-generic」は「linux-image-VERSION」と「linux-image-extra-VERSION」の両方に依存しているため、普通のデスクトップやサーバーにおいてはこれらを区別することはありません。それに対して仮想環境で使われる「linux-image-virtual」は「linux-image-VERSION」のみに依存しています。これは「linux-image-extra-VIRSION」で提供するハードウェアドライバーのほとんどは仮想環境では不要だからです。以前は「linux-image-virtual」は「linux-image-generic」とは別のカーネルだったのですが、14.04ぐらいからカーネルイメージそのものは同一でパッケージの依存関係だけ変えている状態になっています。そのため「linux-image-extra-virtual」をインストールすることと「linux-image-generic」をインストールすることは本質的には同じです。
Dockerで使うaufsのドライバーは「linux-image-extra-VERSION」に入っています。仮想マシンやクラウドインスタンスなど「linux-image-virtual」を使っている環境で、最新の「linux-image-extra-VERSION」をインストールするために上記では「linux-image-generic」を指定しているわけです。ちなみに「linux-image-generic」は常に「リポジトリにある最新のバージョンのlinux-image-extra-VERSIONのパッケージ」に依存しています。しかしながら何らかの理由で「現在そのホストで使っているカーネルパッケージのバージョン」は「リポジトリの最新バージョン」と異なることもあるでしょう。そこで上記では「linux-image-extra-$(uname -r)
」と指定することで「現在使っているカーネルバージョン」のaufsドライバーもインストールしています。
上記を踏まえた上で、カーネルパッケージを明示的にインストールするかどうかを個々の環境にあわせて判断してください。
リポジトリ鍵とリポジトリリストの導入
次にリポジトリのGPG鍵とリポジトリのリストを登録しましょう。
apt-key
コマンドを使えばリポジトリ鍵を管理できます。ただし普段使うことはあまりありません。ちなみにadd-apt-repository
コマンドはPPAの追加でよく使われていますが、上記のように任意のリポジトリURLを/etc/apt/sources.list
に追加するような使い方も可能です。この使い方で注意しなくてはならないのは、PPAのように/etc/apt/sources.list.d/
以下に新規にファイルを追加するのではなく、/etc/apt/sources.list
の末尾に指定した文字列をそのまま追記するということです。別ファイルで管理したい場合は、次のようにecho
コマンドとtee
コマンドを組み合わせる方法を使用しましょう。
将来的にDocker自体が不要になり、リポジトリも使わなくなったら、パッケージやリポジトリURLだけでなくリポジトリ鍵も削除しておきましょう。リポジトリの鍵は次のコマンドで削除できます。
ここ「0EBFCD88
」は鍵IDであり、「apt-key list
」出力結果の中で個々の鍵の作成日時の前に表示される文字列です。
docker-engineパッケージのインストール
リポジトリの準備ができたらパッケージをインストールします。
Ubuntu 16.04 LTSにインストールした場合、systemdのサービスファイルがインストールされて、自動的にサービスが立ち上がります。また再起動後も自動起動する設定になっています。
Dockerクライアントがデーモンを操作するためには、sudo
コマンドを使って管理者権限を取得するか、docker
グループに所属する必要があります。docker
グループに所属しておけば、sudo
なしにコンテナの生成や操作ができますので何かと便利です。このdocker
グループはdocker-engineインストール時に自動的に作成されていますので、あとはユーザーをグループに追加してログインしなおすだけです[5]。
これでインストールは完了です。実際にシンプルなhello-worldコンテナを立ち上げてみましょう。
Ubuntuのdocker.ioパッケージ
Ubuntuのdocker.ioパッケージのインストールは、Ubuntu 16.04 LTS上であれば非常に簡単で、ただdocker.ioパッケージをインストールするだけです[6]。
docker-engineパッケージと同様にsystemdの設定ファイルのインストールや自動起動も設定されていますし、docker
グループも作成されます。ちなみにDocker公式のdocker-engineパッケージはgroupadd
コマンドでグループを作っているのに対して、Ubuntuのdocker.ioパッケージはaddgroup
コマンドでグループを作っているため、グループIDの番号付けのルールが異なっていることに注意してください。docker-engineパッケージと同様に、docker
グループに自分のアカウントを追加しておきましょう。
基本的にDocker公式のdocker-engineパッケージとUbuntuのdocker.ioパッケージは共存できません。どちらか一方をインストールする時は他方はインストールしないでおきましょう。
プロキシの設定
DockerデーモンはHTTPS経由でDocker HubのAPIなどにアクセスします。そのため環境によってはデーモンそのものにもプロキシの設定が必要です。プロキシを設定する方法はいくつか存在しますが、ここではsystemdのドロップインファイルを使ったカスタマイズ方法を紹介しましょう。
systemdの設定ファイルは「/etc/systemd/system
」や「/lib/systemd/system
」などに保存されています。Ubuntuの場合、これらはパッケージによって提供され、原則として内容を変更しなくても「きちんと動く」ようになっています。しかしながら何らかの理由で一部の設定を変えたいことがあるでしょう。「/etc
」以下の設定ファイルとして登録されたファイルであれば、内容を変更したとしてもパッケージのアップデートによって更新される心配はありませんし、何らかの理由で更新されるとしても通知が出るようになっています。しかしながら「/lib
」以下のような設定ファイルとしては扱われないファイルはパッケージの更新によって内容が変わり得ます。
systemdには設定ファイルを部分的に変更する仕組みとして「ドロップイン」が存在します。これはたとえば「/etc/systemd/system
」以下に「Unitファイル名.d
」というディレクトリを作成し、拡張子が「.conf
」のファイルを置いておけば、設定ファイルとして追加で読み込まれるという仕組みです。変更したい部分だけを別ファイルにできるため管理が楽になりますし、パッケージのアップデートで更新される心配もありません[7]。
DockerデーモンのUnit名は「docker.service
」(設定ファイルは/lib/systemd/system/docker.service
)ですので、「docker.service.d
」という名前でドロップインファイル用のディレクトリを作成します。
プロキシの設定は環境変数を指定するだけです。またDockerのローカルリポジトリはプロキシを経由せずにアクセスするようNO_PROXY
の設定も行なっています。
systemdの設定をリロードし、実際に設定が反映されていることを確認しておきましょう。問題なさそうなら「systemctl restart
」でDockerデーモンを再起動します。
ちなみに「systemctl status
」を使えば、実際にドロップインとして使用しているファイルも確認できます。
上記以外の方法として、/etc/default/docker
から環境変数を渡す設定手順も存在します。ただしDocker公式のdocker-engineパッケージの場合はUpstartもしくはSysV Init環境でのみこの設定ファイルを使用し、systemdのUnitファイルからはこの設定ファイルを読まないポリシーにしているようです。Ubuntuリポジトリのdocker.ioパッケージの場合は、/lib/systemd/system/docker.service
においてEnvironmentFile
にこのファイルを指定しているため、systemdでも反映されます。各自の環境に合わせて設定手順を選ぶと良いでしょう。
さて次回はようやくNVIDIA Dockerの話……ではなく、同じコンテナ技術をつかったLXD上でDockerを使う方法を紹介します。