🤖

🤖

:gijutsu_burogu:

俺のコンテナ - libcontainerでコンテナを作ってみた

はじめに

仮想化は使いたいアプリケーションだけでなく OS も含めてまるごと動かす仕組みです。 これでは、ゲスト OS とホスト OS が同じ Linux であればカーネルなどを重複してロードすることになり無駄にメモリを消費してしまいます。

OS のカーネルはホストのものをそのまま使いますが、アプリケーションから見て自由に使える OS 環境があるというのがコンテナです。 アプリケーションがなにをしても全体が壊れない、他へ影響がない箱をイメージです。

Mac 上では コンテナ は動かないので、例えば Docker for Mac では Linux を内部で立ち上げています。

コンテナを支える技術

コンテナを実現するための Linux カーネルの機能にコントロールグループと名前空間があります。

コントロールグループ cgroups

  • CPU
  • メモリ
  • ブロックデバイス
  • ネットワーク
  • /dev以下のデバイスファイル

これらの使用量とアクセスを制限できます。

名前空間 namespace

  • プロセス ID
  • ネットワーク(インターフェース、ルーティングテーブル、ソケット等)
  • マウント(ファイルシステム)
  • UTS(ホスト名)
  • IPC(セマフォ、MQ、共有メモリなどのプロセス間通信)
  • ユーザー(UID,GID)

これらの名前空間を分離できます。 名前空間を分離すると、親となるホスト OS のリソースの許可された一部しか見えなくなり、コンテナが独立してるように見えます。 まるで、自分以外いない世界になります。

コンテナを作ってみた

Docker は Go で書かれており、コアとなるライブラリとしてlibcontainerが使われています。

libcontainer(リブコンテナ)は Go 言語のネイティブな実装であり、名前空間・cgroup・機能・ファイルシステムへのアクセス管理を持つコンテナを作成します。コンテナを作成後、コンテナに対してライフサイクル上の追加操作を可能にします。http://docs.docker.jp/v1.11/engine/reference/glossary.html#libcontainer

github.com

Mac でコンテナが動かないので動作環境も Docker で立てました。 Mac上にDocker(Linux環境)があり、 Docker(Linux環境)上で自作コンテナを動かします。

このリポジトリで作成しました。 github.com

main.golibcontainerでコンテナを作るコードです。 libcontainerのREADMEやテストコードを参考にしました。

1. 自作コンテナでのベースイメージを準備します

$ docker pull alpine
$ docker run --name alpine alpine
$ docker export alpine > alpine.tar
$ mkdir rootfs
$ tar -C rootfs -xvf alpine.tar

2. DockerでLinux環境を作ります

Macでは自作コンテナは動きません。

$ docker build -t orenocontainer .
$ docker run --privileged -it orenocontainer /bin/bash

以下のDockerfileを書きました。

# Dockerfile
FROM golang:1.14

WORKDIR /go/src/github.com/kotaroooo0/orenocontainer

COPY main.go ./
COPY rootfs ./rootfs
RUN go get -v .
RUN go build -o orenocontainer main.go

3. Docker上のLinux環境で自作コンテナを動かします

Goで書いた自作コンテナを起動します。

# Dockerコンテナ内
$ orenocontainer
/bin/sh: 0: can\'t access tty; job control turned off

# 自作コンテナ内
$ go
/bin/sh: 7: go: not found
$ hostname
83409d06ecab
(TODO: これをconfigで設定したtestingに表示できるようにしたい)
$ exit
(Dokerコンテナに戻る)

自作コンテナのホストであるDockerではgoコマンドが使えましたが、自作コンテナ内では使えなくなっています。 これは名前空間を分離したことにより実現されました。

残念な点として、hostnameした際にDockerコンテナと同じホスト名が表示されてしまいました。 ここは、main.goで定義したホスト名(testing)が表示されてほしかったです。

exitでDockerからホスト(Mac)に戻れるように、exitコマンドで自作コンテナからDockerに戻ることができます。

おわりに

Dockerでも使われているlibcontainerを使って、コンテナ自作をしてみました。 hostnameで期待通りの動作をすることはできませんでした。 今後また改善していけたら良いなと思います。 また、Macでコンテナを開発するの厳しいなと感じました。