My External Storage

Feb 15, 2018 - 4 minute read - Comments - go

[Goならわかるシステムプログラミング]libcontainerで実装したLinuxコンテナを起動するためのDockerfile

Goならわかるシステムプログラミング ― 第20回 Go言語とコンテナ
http://ascii.jp/elem/000/001/502/1502967/

Goならわかるシステムプログラミングの中で、GoとlibcontainerライブラリでLinuxコンテナを実装する回があるのだが、 実装したコンテナはLinux上でしかgo buildできないし、起動もできなかった。VirtualBoxなどでも良いが、Dockerで環境を用意するようにした。

今回作成したDockerfileなどは以下にある。

budougumi0617/gsp/ch17/container
https://github.com/budougumi0617/gsp/tree/master/ch17/container

TL;DR

  • 「Goならわかるシステムプログラミング Go言語とコンテナ」のサンプルコードをmacOSやWindowsでも動かせるようにDockerfileを作成した
  • 起動したAlpineコンテナの中でlibcontainerで実装した自作(写経)コンテナを起動できた
  • docker runするときに--privilegedオプションをつけておくこと

背景

Goならわかるシステムプログラミングの「第17章 Go言語とコンテナ」では libcontainerライブラリを使ってGoでコンテナを実装し起動する。

Goならわかるシステムプログラミング
https://amazon.jp/dp/4908686033

opencontainers/runc/libcontainer
https://github.com/opencontainers/runc/tree/master/libcontainer

Web上の連載で言うと第20回になる。

Goならわかるシステムプログラミング ― 第20回 Go言語とコンテナ
http://ascii.jp/elem/000/001/502/1502967/

ただし、Linux上でしか起動しないコンテナなのでmacOS(Windows)上ではgo buildすらできない。

本中のサンプルコードを実装する

Dockerfileをそのまま利用する場合は本(連載)の中のコードを_main.goという名前で写経する。

https://github.com/budougumi0617/gsp/blob/master/ch17/container/_main.go

Linux上でそれなりに準備しておかないとビルドに失敗するので、_付きの名前で後で作成するコンテナ内でしかビルドしないようにしておいたほうが良い。
build constraints// +build linuxもつけているのだが、自分のCircle CIのビルドだとLinux上でのビルドのはずなのに失敗した。

Dockerfileを作成する

Dockerfileの内容は以下。alpineベースのコンテナにgo buildするときに要求されるライブラリを入れた後、ビルドするだけの単純な構成。

FROM golang:1.9.4-alpine3.7

RUN apk add --update openssl-dev pcre-dev git gcc musl-dev linux-headers sudo

WORKDIR /go/src/github.com/budougumi0617/gsp/ch17/container/
ADD _main.go ./main.go
ADD rootfs ./rootfs/
RUN go get -v .
RUN go build main.go
CMD echo "test"

alpineコンテナだとインクルードファイルなどが入っていないのでもろもろapk addしておく。
また、コンテナに入って自作コンテナでいろいろコマンドを実行するのが目的のためエントリはただのechoにしてある。

本(連載)に記載されているrootfsディレクトリにalpineコンテナから抽出したもろもろのファイルを入れる作業は Dockerfile外で行う必要があるので注意。

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

これで自作(写経)コンテナを実行してみる準備ができた。

docker runするときは–privilegedオプションをつけること

docker buildの中でgo buildするので、あとはコンテナに入って実際に起動してみる。
ここでオプションをつけずにそのままdocker runをすると以下のようなエラーで終了してしまう。

$ docker build -t build-container .
$ docker run -it build-container /bin/ash
/go/src/github.com/budougumi0617/gsp/ch17/container # sudo ./main
WARN[0000] signal: killed
2018/02/14 00:43:37 container_linux.go:348: starting container process caused "process_linux.go:279: applying cgroup configuration for process caused \"mkdir /sys/fs/cgroup/cpuset/system: read-only file system\""

syscallする権限が不足しているのが原因らしいので、--privilegedをつけてdocker runする。

$ docker build -t build-container . --no-cache=true
$ docker run --privileged -it build-container /bin/ash
/go/src/github.com/budougumi0617/gsp/ch17/container # ./main
/bin/sh: can't access tty; job control turned off
/ # /bin/hostname
testing
/ # exit
/go/src/github.com/budougumi0617/gsp/ch17/container # exit

ちょっとTTYの設定は出来ていないが、ちゃんと実行することができた。

おわりに

alpine linuxベースのコンテナを実行させるためにalpine linuxコンテナを作るというやや本末転倒気味のことしているのはご愛嬌。
頑張れば作業工程のalpine.tarを作る工程は削除できそうなのだが、目的は達成したのでここまでにしておく。
去年の今頃Dockerの本一冊読んだのだが、Dockerfileの書き方をすっかり忘れていた。やはり日頃の継続と反復が大事である。

参考

Goならわかるシステムプログラミング
https://amazon.jp/dp/4908686033

Goならわかるシステムプログラミング ― 第20回 Go言語とコンテナ
http://ascii.jp/elem/000/001/502/1502967/

budougumi0617/gsp/ch17/container
https://github.com/budougumi0617/gsp/tree/master/ch17/container

opencontainers/runc/libcontainer
https://github.com/opencontainers/runc/tree/master/libcontainer

GoのBuild Constraintsに関するメモ
https://qiita.com/hnw/items/7dd4d10e837158d6156a

Docker privileged オプションについて
https://qiita.com/muddydixon/items/d2982ab0846002bf3ea8

関連記事