Moby Projectによる新たなImmutable infrastructureの可能性


Dockerconf2017で発表のあったlinuxkitとMoby Project。
デモを見て衝撃を受け、今後のDockerに新たなImmutable infrastructureの可能性を感じたので調べたり試したりしてみました。
実際に動かしてみたスクリーンショットも載せてあります。

皆さんにも僕の感じた衝撃と可能性を知ってもらいたいです。是非最後まで読んでいってください！

(20170419 10:00 編集) Moby Projectとlinuxkitについて認識が違っていたことに気付いたので修正しました。

## これを読んでわかること

- Moby Projectとlinuxkitの概要
- mobyを使ってbuildやrunをする方法
- mobyを使ってGCPでインスタンスを立てる方法

## 環境

OS: MacOSX Sierra
Go: version 1.8.1
docker: version 1.13.1

## 前置きと解説

動かす方法だけ知りたい、という人はスキップしてください。

### 2016年のDocker

![](https://i0.wp.com/blog.docker.com/wp-content/uploads/LinuxConBerlin-Docker-16x9.001.jpeg?w=1920&ssl=1)
[出典](https://blog.docker.com/2016/10/introducing-infrakit-an-open-source-toolkit-for-declarative-infrastructure/)

Dockerコンテナはポータビリティに優れたアーキテクチャでしたが、当初はLinuxでしか動かず、macやwindowsではdocker-machineなどの仮想環境上にdockerをインストールして使うしかありませんでした。

#### Docker for mac, windows

しかし、2016年にDocker for macやDocker for windowsがリリースされました。
macOS上では[hyperkit](https://github.com/moby/hyperkit)、windows上ではhyper-Vを使っておりネイティブではありませんでしたが、VM構築などの作業をしなくてもdockerを動かせるようになりました。

#### infrakit

dockerは2016年の10月にinfrakitというものをリリースしています。あんまり注目してなかったので詳しくは知りません。
詳しくはこちら： http://www.publickey1.jp/blog/16/dockerinfrakitdocker.html

> InfraKitはこうしたクラウドごと、環境ごとに異なるDocker環境の構築と運用の自動化と共通化をすることで、Dockerの導入と運用を容易にしてしまおうというもの。さまざまな環境に対応するため、プラガブルな構造になっています。
> これは差別化による優位性を実現しようとするクラウドベンダーに対して、クラウド基盤の差別化を吸収し抽象化して共通化してしまおうというDocker側の試みといえます。

#### windowsコンテナ

![](http://acom.azurecomcdn.net/80C57D/blogmedia/blogmedia/2014/10/15/WindowsServerContainer_thumb.png)

[出典](https://azure.microsoft.com/en-us/blog/new-windows-server-containers-and-azure-support-for-docker/)

Windows Server 2016やWindows 10 Anniversary Update以降ではWindowsコンテナが使えるようになりました。
詳しくはこちら： http://www.atmarkit.co.jp/ait/articles/1611/04/news028.html

今回のkeynoteでもazureのアーキテクトが登壇され、Azure上でのWindowsコンテナのデモを行っていました。
https://blogs.technet.microsoft.com/hybridcloud/2017/04/18/dockercon-2017-powering-new-linux-innovations-with-hyper-v-isolation-and-windows-server/

#### docker swarm mode

docker v1.12ではdocker swarm modeがdocker engineに統合されました。
docker stackコマンドによりdocker-composeファイルを使ったデプロイや、内部KVS・内部LBなどが搭載されDockerコンポーネント内でのオーケストレーションやデプロイ機能が大幅に強化されました。

### これまでの流れ

このように、2016年のdockerはオーケストレーションやクラウド環境など、今までのコンテナのよりも一歩上の枠組みへの挑戦を進めてきたといえると思います。
そして、今回のDockerCon2017ではこれらのさらに上のレイヤーにまで大きく枠組みを広げてきました。それでは本題に入りましょう！

## Moby ProjectとLinuxkit

### Moby Project

https://mobyproject.org/

> Moby is an open project created by Docker to advance the software containerization movement. It provides a “lego set” of dozens of standard components and a framework for assembling them into custom platforms.

http://www.atmarkit.co.jp/ait/articles/1704/19/news051.html

> Moby Projectは、Dockerがこれまで開発してきた80以上のコンテナ関連ソフトウェアコンポーネントを取捨選択し、他のコンポーネントとレゴのように組み合わせて、カスタムのコンテナシステムを作り上げられる環境を提供するオープンソースプロジェクト。

Docker社はこれまでの資産を活用してさらに大きな枠組みでのプラットフォーム化を目指そうというのがこれからの流れのようです。
keynoteでも「これからはコンテナをメインストリームに」「developerの開発サイクルを早く回すことを大事にしたい」というような言葉もあり、Dockerがこれまで目指してきた抽象化をもっとハイレベルなレイヤーで目指していく姿勢を見せています。

そのDockerを取り巻くコンポーネントの1つとして、合わせて発表されたのがlinuxkitです。

### LinuxKit

今日のDockerConf2017で発表されたツールがLinuxKitです。
しかも、keynote中にLiveでprivateリポジトリからpublicリポジトリに切り替えられ、OSS化されました。カッコイイ。
https://github.com/linuxkit/linuxkit

下記記事がannounceです。
https://blog.docker.com/2017/04/introducing-linuxkit-container-os-toolkit/

> Last year, one of the most common requests we heard from our users was to bring a Docker-native experience to their platforms. These platforms were many and varied: from cloud platforms such as AWS, Azure, Google Cloud, to server platforms such as Windows Server, desktop platforms that their developers used such as OSX and Windows 10, to mainframes and IoT platforms –  the list went on.


公式リポジトリではこう紹介されています。

> LinuxKit, a toolkit for building custom minimal, immutable Linux distributions.

LinuxKitはcontainerdが動くための最小限のLinuxをビルドするためのツールキットで、Immutable infrastructureであるDockerコンテナをLinux distributionとして配布するためのものです。
これだけの説明だとあまりピンと来ていなかったんですが、次に紹介されたMoby Projectとその中のデモで目指すビジョンが伝わってきました。
（この後の僕の説明とGetting Startedで少しでも伝われば、と思いますが…）

![Pasted image at 2017_04_19 00_48.png](https://qiita-image-store.s3.amazonaws.com/0/37715/ab9bc949-b771-38a8-1573-62f6af7383af.png "Pasted image at 2017_04_19 00_48.png")

デモではredisのコンテナが使われていたので "RedisOS"と書かれています。
下の紫色の枠がホストOS部分、そして上の青い枠で囲われている部分が "RedisOS" と紹介されている部分です。

linuxkitのmobyコマンドを使うことでこの青い枠の部分をパッケージングしてビルドすることが出来ます。
今まではLinuxカーネルなどに依存していたDockerですが、linuxkitによりminimum linux distributionとして上の部分がパッケージとして提供されます。

Linux distributionのoutput formatとして下記のようなものがサポートされています。

- kernel + initrd (for hyperkit)
- iso-bios (for Qemu)
- iso-efi (for Hyper-V)
- vmdk (for vmware)
- iso-bios (for CD image)
- gcp-img (for **Google Cloud Platform!**)

参考： https://github.com/linuxkit/linuxkit/blob/master/docs/yaml.md#output

linuxkitはこれらのformatでビルド結果を出力することができます。
気づかれた方も多いと思うのですが、これらのファイル形式はいずれも **OS配布に使われるファイル形式** です。

そう、今までDockerコンテナはOSの中で動く1つのプロセスでした。
しかし、mobyを使うことによって **OSレベルでのImmutable infrastrcureを実現できる** と言えます。

### linuxkitによって受けた衝撃

特に最後の `gcp-img` が大きな衝撃でした。

今まではDockerの動作環境を構築したり、ベンダーロックインを受けながらクラウド上にDockerの動作するOSをホスティングしていましたが、mobyを使うことによって **OSレベルでのimmutable infrastructure** が実現されています。

```
プロセスレベルのImmutable Infrastructure　→　OSレベルのImmutable Infrastructureへ
```

さらに、上記にもあったinfrakitはpluggableで、mobyは[内部的にinfrakitを使っているように見える](https://github.com/linuxkit/linuxkit/blob/master/src/cmd/infrakit-instance-hyperkit/main.go#L13)ので、恐らくmobyもpluggableな仕組みになっているはずです（linuxkitのREADMEにも書いてます）。

つまり、pluginが作られているクラウド環境であれば **どの環境にも開発環境でビルドされたOSを持ち込み、サーバを起動することが可能** なのではないでしょうか。

もはやサーバにprovisioningなど不要。
linuxkitを使うことでOSをビルドしてクラウドに持ち込み、古いインスタンスをそのまま捨てて新しいインスタンスを起動するのがデプロイになってしまう可能性まであります。
冪等性とはなんだったんでしょう。

## Getting Started

さて、というわけで早速試してみましょう。
といっても何も難しいことはありません。公式のREADME通りにすれば動きます。

※動かすにはgoとdockerが必要です。GOPATHも通しておいてください。

### 環境構築

docにはbuildする手順が書いてましたが、go getでそのまま使えるみたいだったので手っ取り早くgo getします。

```bash
# moby
$ go get -u github.com/docker/moby/src/cmd/moby
# infrakit-instance-hyperkit -> macユーザ(hyperkitを使う人)以外は不要だと思います
$ go get -u github.com/docker/moby/src/cmd/infrakit-instance-hyperkit
```

これで環境構築は終わりです。
`moby help` を実行してhelpが表示されることを確認してください。

### build

公式のexampleをbuildしてみましょう。

```bash
# 作業用ディレクトリに移動
$ cd tmp
# exampleのymlファイルをダウンロード
$ curl https://raw.githubusercontent.com/linuxkit/linuxkit/master/examples/sshd.yml > sshd.yml
$ moby build sshd.yml
```

![Kobito.Ud6h85.png](https://qiita-image-store.s3.amazonaws.com/0/37715/f4f08658-aea5-a823-82b0-7222f2f5740c.png "Kobito.Ud6h85.png")

このsshd.ymlのformatは以下のようになっています。

```yml
outputs:
  - format: kernel+initrd
  - format: iso-bios
  - format: iso-efi
```

build自体はすぐ終わります。buildが終わったら成果物を確認しましょう。
![Kobito.FBtdKG.png](https://qiita-image-store.s3.amazonaws.com/0/37715/5788c24a-d4e3-8a51-b22a-d644bfe1472f.png "Kobito.FBtdKG.png")

これらのファイルができていれば成功です。

### run

では起動してみましょう。

```bash
$ moby run hyperkit sshd
```

macなのでbackendにhyperkitを指定しています。
なお、backendを省略した場合以下のような優先順位でbackendが指定されます。

```bash
$ moby run --help
...（省略）
If not specified the platform specific default will be used
Supported backends are (default platform in brackets):
  gcp
  hyperkit [macOS]
  qemu [linux]
  vmware
  packet
```

`moby run sshd` を実行すると、ログが流れて下記のような画面になりました。

![Kobito.W9DhJ8.png](https://qiita-image-store.s3.amazonaws.com/0/37715/65757d07-59c4-842a-9044-40bbbb8b0acf.png "Kobito.W9DhJ8.png")

sshdが起動しているか、確認してみましょう。

![Kobito.stOIMF.png](https://qiita-image-store.s3.amazonaws.com/0/37715/3e57a4dc-d3da-5d1a-e3db-603ce016dbe7.png "Kobito.stOIMF.png")


はい、 **たった数秒でsshdのコンテナが起動したOSが起動しました** 。
今の気持ちはこんな感じなはずです

<img src="https://qiita-image-store.s3.amazonaws.com/0/37715/bfcb4ff3-f407-dc8b-0d78-2b85637be801.png" width="60%">


起動したOSは `halt` で終了します。

![Kobito.WXha3S.png](https://qiita-image-store.s3.amazonaws.com/0/37715/b37b652a-3a46-a3f2-0241-7f35ed987b4f.png "Kobito.WXha3S.png")

これでOSごと綺麗サッパリなくなりました。

## GCPでの起動

さて、では次にGCP上でインスタンスを起動してみましょう。

### 準備

これを行うにはGoogle Cloud Platformのアカウントとgoogle-cloud-sdkが必要です。
詳しくは説明しませんが、linuxkitの公式にもドキュメントがあるのでこちらも参考にしつつセットアップしてください。
https://github.com/linuxkit/linuxkit/blob/master/docs/gcp.md

google-cloud-sdkとGCPアカウントの準備が終わったらドキュメントに従って下記のコマンドでloginします。

```bash
export CLOUDSDK_CORE_PROJECT=<GCP project>
export CLOUDSDK_COMPUTE_ZONE=europe-west1-d
gcloud auth login
```

次に、[こちら](https://cloud.google.com/compute/docs/access/create-enable-service-accounts-for-instances#createanewserviceaccount)の手順にしたがってサービスアカウントを作成します。

![Kobito.cH2zUi.png](https://qiita-image-store.s3.amazonaws.com/0/37715/1dad56a4-15e2-1871-b99a-6c5c4b9c93fa.png "Kobito.cH2zUi.png")

作成時にはこちらのチェックを入れてJSONファイルをダウンロードしましょう。
ファイルをダウンロードしたら、service-accountで認証します。

```
$ gcloud auth activate-service-account [ACCOUNT] --key-file=KEY_FILE
```

また、gcpのイメージのインポートにはgoogle cloud storageを使うので権限が必要です。
IAMで権限を割り振ってください。

![Kobito.CHXyKR.png](https://qiita-image-store.s3.amazonaws.com/0/37715/73f58f60-ec38-a1f3-ed90-d52bfb16e983.png "Kobito.CHXyKR.png")

ウィンドウが開くので、メンバーに先程作ったサービスアカウントを、権限にProjectの編集者を与えます。

![Kobito.HL9aPo.png](https://qiita-image-store.s3.amazonaws.com/0/37715/498eaada-b748-b9fd-22ae-83ead00a8228.png "Kobito.HL9aPo.png")

さらに、アップロード先のGCSのバケットを作成します。

![Kobito.wDcHu9.png](https://qiita-image-store.s3.amazonaws.com/0/37715/68c28fd9-c863-bdaa-fe0b-6e2f316b9cc6.png "Kobito.wDcHu9.png")

バケット名はあとで使うので控えておいてください。
ここまでで準備完了です。

### ビルド

exampleのgcp.ymlをダウンロードしてビルドします。

```
$ curl https://raw.githubusercontent.com/linuxkit/linuxkit/d422c70ac6da78da3d32237735d86eb9001df384/examples/gcp.yml > gcp.yml
```

ダウンロードしたgcp.ymlのbucket名を、さっき作ったバケット名とプロジェクト名に指定します。

![Kobito.9WwqwZ.png](https://qiita-image-store.s3.amazonaws.com/0/37715/7307d259-ad41-42bf-0411-9ef979627956.png "Kobito.9WwqwZ.png")


あとは普通にbuildします。

```
$ moby build gcp.yml
```

![Kobito.3BvIP3.png](https://qiita-image-store.s3.amazonaws.com/0/37715/b0517991-18dd-b31d-1753-99fb27636ada.png "Kobito.3BvIP3.png")

buildと同時にtarのuploadとimageの作成が行われます。
コンソールからも確認してみましょう。

![Kobito.rKoLPo.png](https://qiita-image-store.s3.amazonaws.com/0/37715/663e4e68-f785-b4b5-4d23-540fe4e4b5b9.png "Kobito.rKoLPo.png")

一番上が今作成したイメージです。出来てますね。

### run

ではrunしてみましょう。

```bash
$ moby run gcp -project myproject gcp # myprojectを自分のプロジェクト名にする
```

![Kobito.DTTPuO.png](https://qiita-image-store.s3.amazonaws.com/0/37715/f604e941-06eb-6a19-2f4a-76f9c8e40673.png "Kobito.DTTPuO.png")

さくっとインスタンスが作成されました！

![Kobito.q3tSsw.png](https://qiita-image-store.s3.amazonaws.com/0/37715/fc94cfb9-724c-9e96-1521-7284265f174d.png "Kobito.q3tSsw.png")

nginxのプロセスも動いてるようです。
コンソールからも確認してみましょう。

![Kobito.pgRr84.png](https://qiita-image-store.s3.amazonaws.com/0/37715/e40e6d5e-af99-a519-903f-333126ce5464.png "Kobito.pgRr84.png")

ちなみにhaltしてインスタンスが消えるのも確認したかったんですが、打ったらハングアップしてしまいました……
まあご愛嬌ということで
とりあえず今回はここまでで(´・ω・`)

あ、使ったインスタンスやバケットは料金がかからないように消しておいてくださいね。

## まとめ

いかがだったでしょうか。
僕の感じた **新たなImmutable infrastructureの可能性** に少しでも共感してもらえれば幸いです。
まだ発表されてすぐですし、Docker界隈は流れが早いので、この情報もすぐに古くなっていくかもしれませんが、頑張って追いかけていきましょう！