Go
vagrant
docker
CoreOS
Rocket

「Docker」と新コンテナランタイム「rkt」をサクっと比較してみる

More than 1 year has passed since last update.

概要

この記事では、アプリケーションコンテナのランタイムであるDockerとrktについて、
2つの大まかな違いを説明し、Dockerとrktそれぞれを使用してコンテナの取得・作成・起動・破棄など基本的なコンテナ操作を実施してみます。
記事全体として「Dockerはある程度知ってるけど、それに比べてrktってどうなんだ?」というトーンで書いています。

Dockerとは

公式:https://www.docker.com/

Docker社が開発しているオープンソースのコンテナランタイムです。
コンテナ技術自体は決して新しくはないですが、その使いやすさからある種のコンテナブーム(?)を巻き起こしたともいえるかと思います。
詳しい情報は、ググれば良い記事が山ほど出てくるので割愛します。

rktとは

公式:https://coreos.com/rkt/docs/latest/

CoreOS社が開発している、アプリケーションコンテナのランタイムとなります。
同社が2014年12月に発表したApp Container(appc) Specという標準的なコンテナの仕様を実装したもので、「an alternative to the Docker runtime」として注目を集めています。
現時点での最新バージョンは0.6.1とまだまだプロトタイプの位置づけです。
ちなみにこれまで「rocket」や「Rocket」といった表記が混在していましたが、今後は「rkt」に統一されるらしいです。

Dockerとrktの違い

appcのテーマである「構成の柔軟性」「セキュリティ」「イメージ配布の容易さ」「オープンさ」の切り口で説明してみます。

  1. 構成の柔軟性
    Dockerは、クラウドサーバやクラスタ向けシステムを構築するためののツールや幅広い機能(イメージの作成・動作・アップロード・ダウンロード)が、rootで動作するmonolithicなバイナリで提供されています。
    一方でrktにおいては、コンテナをダウンロード、インストール、起動するための全てのツールは統合されてはいますが、それぞれは独立した構成となっています。

  2. セキュリティ
    Dockerはクラサバ型の設計であり、Dockerクライアントは Dockerデーモンに対して各種コマンドを発行するアーキテクチャとなっています。
    Dockerデーモンはroot権限で動作する必要があるため、常にrootプロセスがDockerホスト側で動き続けることになります。
    このことを「全てが中央のデーモンを通じて実行されるDockerの処理モデルには、セキュリティと再利用性において根本的な欠陥がある。」とし、root権限デーモン⇔クライアントのアーキテクチャを廃止して新たに生まれたのがrktとなります。

  3. コンテナイメージの配布
    Dockerは「Docker Hub」や「Docker Private Registry」などのレジストリを通じてコンテナイメージをpull/pushする必要があります。
    rktにおいては専用のレジストリは存在せず、WEBの標準的な仕様(HTTPS)を用いてイメージを配布することができます。

  4. オープンさ
    rktはオープンなコンテナ仕様を実装しています。

コマンドレベルでの細かな違いについては、下記で順を追って見ていきましょう。

環境

coreos(alpha v717.0.0) on vagrant(1.7.2)

インストール

coreosは、アプリケーションをコンテナ上でのみ動作させるように設計されており、
取得したbox(coreos-alpha v717.0.0)ではDocker, rkt共にインストール済みとなっています。

Docker

$ docker -v
Docker version 1.5.0, build a8a31ef-dirty

rkt

$ rkt version
rkt version 0.5.5
appc version 0.5.1+git

ちなみに現時点(2015/6/21)でのrktの最新バージョンは0.6.1となっており、下記の通り最新版をインストールすることもできます。

wget https://github.com/coreos/rkt/releases/download/v0.6.1/rkt-v0.6.1.tar.gz
tar xzvf rkt-v0.6.1.tar.gz

コンテナの取得・作成・起動から破棄まで

コンテナイメージの取得

Docker

Dockerは「Docker Hub」や「Docker Private Registry」などのレジストリを介してイメージを取得・公開することができます。
ここではCentOSの最新イメージを取得しています。

$ docker pull httpd

rkt

rktでは、appcのディスカバリ仕様に従って、インターネット上からコンテナイメージを取得することができます。
ここでは「coreos.com/etcd」というACIを取得する例を示します。

① rkt trust
rktではACIの署名を検証するために公開鍵を取得する必要があります。

$ sudo rkt trust --prefix=coreos.com/etcd

② rkt fetch
次にrkt fetchコマンドでACIの取得、署名の検証を行います。

$ sudo rkt fetch coreos.com/etcd:v2.0.4

なお、Dockerイメージを利用したい場合にDocker Registryからイメージダウンロードし、ACIに変換することもできます。

$ sudo rkt --insecure-skip-verify fetch docker://httpd

※Dockerイメージのsignature verificationはサポートされないため、--insecure-skip-verifyオプションを付けます。

コンテナイメージ一覧

Docker

docker imagesコマンドを使用します。

$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
httpd               latest              de94ed779434        5 days ago          161.8 MB

rkt

rkt imagesコマンドを使用します。

$ sudo rkt images
KEY                                                                     APPNAME                 IMPORTTIME                              LATEST
sha512-1eba37d9b344b33d272181e176da111ef2fdd4958b88ba4071e56db9ac07cf62 coreos.com/etcd:v2.0.4  2015-06-21 07:38:58.396 +0000 UTC       false
sha512-fb95bcc29323607aafcca362bd6beb073c85e34f4cd63db8fe5570b603d33838 httpd:latest    2015-06-21 10:47:48.825 +0000 UTC       false

取得した「coreos.com/etcd」と「httpd」イメージが表示されています。

コンテナの起動

Docker

docker runコマンドを使用します。
-pオプションでコンテナの80番ポートをホストの8080ポートをマッピングします。

$ docker run -p 8080:80 httpd:latest

ホスト側からコンテナへアクセスしてみます。

$ curl http://localhost:8080/
<html><body><h1>It works!</h1></body></html>

rkt

rktではrkt runコマンドでイメージ名を指定することでコンテナを起動します。

$ sudo rkt run -local httpd

-local:ローカルのイメージを利用する

rktのネットワーキングはdockerと異なりデフォルトでホストモードとなっており、ネットワークはホストのものを使用します。

$ curl "http://localhost:80/"
<html><body><h1>It works!</h1></body></html>

プライベートネットワークを利用する場合は、rkt metadata-serviceコマンドでMetadata Serviceを起動したのちに--private-netオプションを使用してコンテナを起動します。

$ sudo rkt metadata-service

後述のrkt listコマンドでコンテナのIPを確認し、アクセスしてみます。
ここでは試しませんが、イメージのビルド時にポートのエントリを定義しておけば、rkt run時に--portオプションを使用することでポートフォワーディングも実現できます。

$ curl "http://172.16.28.3:80"
<html><body><h1>It works!</h1></body></html>

コンテナを落としたいときは、Ctrl-]を3回押します。

コンテナ一覧

Docker

$ docker ps
CONTAINER ID        IMAGE               COMMAND              CREATED             STATUS              PORTS                  NAMES
21763385c6bc        httpd:latest        "httpd-foreground"   5 seconds ago       Up 4 seconds        0.0.0.0:8080->80/tcp   trusting_yalow

rkt

$ sudo rkt list -full
UUID                                    ACI     STATE   NETWORKS
26804adf-6394-469d-bb0c-ff7168202368    httpd   running default:ip4=172.16.28.3

コンテナの作成(ビルド)

Docker

コンテナの構成内容を記載したDockerfileを指定してdocker buildコマンドでビルドを行います。

① dockerfile作成
下記は簡単な例となりますが、dockerfileは命令 引数の形式で記載をします。

dockerfile
# ベースイメージ
FROM centos
# 作成者
MAINTAINER sample
# 各種コマンドの実行
RUN yum -y install httpd
# コンテナの実行コマンド
CMD /bin/bash

② ビルド
dockerfileのディレクトリを指定してdocker buildコマンドを実行します。

$ docker build -t myimage ./

③ イメージ確認

$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED              VIRTUAL SIZE
myimage             latest              df2ca7e6d2e1        About a minute ago   263.5 MB

rkt

rktのコンテナイメージはACIフォーマットで管理され、appcで提供されているツール「actool」を使用することでビルドできます。
actoolではコンテナの構成内容を記載したJSON形式のMANIFESTファイルとルートファイルシステムを元にACIをビルドします。

① MANIFEST作成
今回は、公式リファレンスを参考にGO言語製サンプルアプリケーションを実行するACIを作成します。
https://github.com/coreos/rkt/blob/master/Documentation/getting-started-guide.md

manifest
{
    "acKind": "ImageManifest",
    "acVersion": "0.6.0",
    "name": "myimage",
    "labels": [
        {"name": "os", "value": "linux"},
        {"name": "arch", "value": "amd64"}
    ],
    "app": {
        "exec": [
            "/bin/hello"
        ],
        "user": "0",
        "group": "0"
    }
}

② ディレクトリ整備

$ mkdir myimage
$ mkdir myimage/rootfs
$ mkdir myimage/rootfs/bin
# manifest配置
$ mv manifest myimage/

③ GOアプリケーション作成

hello.go
package main

import (
    "log"
    "net/http"
)

func main() {
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        log.Printf("request from %v\n", r.RemoteAddr)
        w.Write([]byte("hello\n"))
    })
    log.Fatal(http.ListenAndServe(":5000", nil))
}
$ CGO_ENABLED=0 GOOS=linux go build -o hello -a -tags netgo -ldflags '-w' .
$ mv hello myimage/rootfs/bin/

④ ビルド

actool build myimage my-app.aci

⑤ コンテナ起動

$ sudo rkt --insecure-skip-verify run myimage.aci

⑥ ホストからアクセス確認

$ curl "http://localhost:5000"
hello

コンテナの削除

Docker

CONATINER IDを指定してdocker rmコマンドを実行します。

$ docker rm 01fdf4b430b9
01fdf4b430b9

rkt

現時点でコンテナの削除コマンドは存在しないみたいです。

コンテナイメージの削除

Docker

IMAGE IDを指定してdocker rmiコマンドを実行します。

$ docker rmi de94ed779434
Untagged: httpd:latest

rkt

現時点でコンテナイメージの削除コマンドは存在しないみたいです

まとめ

簡単ではありますが一通りDockerとrktを触ってみました。
冒頭にも述べたとおりrktはプロトタイプの段階であるため、機能的にも使いやすさ的にもDockerにまだまだ劣ると感じています。
実用という点について現段階では多く語れませんが、Dockerのセキュリティ面での問題を解消したというのは言わずもがな、何よりオープンかつシンプルなrktの思想は素敵だと思います。
2015年5月に「Kubernetes」がrktを通じappcサポートすることを明らかにしたこともあるように、今後の可能性に期待したいと思います。

参考