かえるの井戸端雑記

開発日誌的な記事だったり備忘録だったり。まとめ記事と言うよりは、七転八倒の様子を小説みたいに読んで眺めてもらえればと。

DockerでC++環境を作った時のメモ

元々はC++でちょっとしたtoolを作っていたのだけれど、Mac上でのclangとboostのversion問題にぶつかってうまく解決出来なかったので、思い立ってDockerで開発環境組もうか、となった。

で、人に教えてもらいながら作ったものが以下。

github.com

ということで以下そのときの覚書。

Dockerに関する調べ物

まずもってDockerについてぼんやりとしか知らない。 これを使ったのもかつてboot2dockerでVirtualBoxを用いてVM立ち上げていた頃のこと。 再学習が必要なのでは? ということでしてみた。

現時点で把握していること

Dockerの実行構成の理解が曖昧なので整理。正確にはDockerを使うときにimageとcontainerがあるけれど、これらの関係。 いまのところの理解としてはVirtualBoxなどのVM上でimageとなるOSを起動してそこでContainerを動かしているという理解だけど、今はVirtualBoxいらないよねとか、じゃあそこは何が代替しているんだろうとか、Dockerfileで最初に生成されるのはimageであってContainerではない? とか、そのあたりがぐちゃぐちゃになっている。

ImageとContainerについて

ContainerがOSのresouceをうまくnamespaceみたく分割して利用しているものなのはわかる。

だから任意のOSのContainerを動かしたいという場合は、imageから起動したVMが必要だし、VM上でContainerを立ち上げるしかない。

で、Dockerfileは最初baseとなるimageを落としてからいろいろinstallして、その結果として新しいimageを作っている……のか?

qiita.com

Docker(ドッカー)イメージはコンテナの元だ。例えば、MySQLを運用するコンテナはMySQLイメージで起動する。ドッカーイメージはDockerfile (ドッカーファイル)で定義する。

それでいいらしい。ではDockerfileに関する謎は解けた。

VMについて

次、mac上でいろんなimageを動かしている方法。 昔はboot2ddockerを用いてvirtualboxを利用していたけれど、今はそれは必要ない。 じゃあ何がその代わりをしているんだっけ。結構前にmac標準でそういう機能が入ったと思うんだけど。

qiita.com

Macはxhyveを利用し、WindowsHyper-V(windows10以降)を利用する

ああ文字列には見覚えがある。

qiita.com

Appleがついに公式にサポートした仮想化技術Hypervisor.frameworkを使って、FreeBSDのbhyveをOS Xにポートしたxhyveというものが以前GitHubにされました。

github.com

The xhyve hypervisor is a port of bhyve to OS X. It is built on top of Hypervisor.framework in OS X 10.10 Yosemite and higher, runs entirely in userspace, and has no other dependencies. It can run FreeBSD and vanilla Linux distributions and may gain support for other guest operating systems in the future.

うーん? hypervisorってそういえば何だっけ。 ぼんやりとVMの管理のためのツール的なものだと思っていたけどもしかしてVM環境自体も担っている?

thinkit.co.jp

ハイパーバイザー型は、サーバーへ直接インストールし仮想マシンを稼働させる方式で、ESXi、Hyper-VXen などが分類されます。ホストOSを必要としないためハードウェアを直接制御することができ、仮想マシンの速度低下を最小限に抑えることができます。また、複数の仮想マシンを効率よく稼働させるための様々な仕組みが盛り込まれています。

ハイパーバイザ - Wikipedia

ハードウェア上でまず別のOSが稼働し(このOSをホストOSと呼ぶ)、その上でハイパーバイザが(ホストOSのアプリケーションとして)稼働し、更にはハイパーバイザの上で更に別のOS(このOSをゲストOSと呼ぶ)を稼働させる方法である。狭義においては、Type 2はハイパーバイザには含まれない。

ああ。そういうこと。

ということで事前知識としてはこんな感じでいいか。

環境構築

最終的にこういう感じになる

少しだけ解説すると、file構成は以下の通り。

Name Description
/doc 開発時の覚書をMarkdownで書きためている場所。きっと整理すればManualになったり開発記録になったりする。
/etc containerで利用するconfiguration fileやdocker関連のfileとかが置いてある。
/src 開発するprogramのsource codeは全部ここ。ここだけ取り出せばそれ単体で開発対象が丸ごと持って行けるというイメージ。

で、どう説明していこうか

いや使い方を説明するなら

  1. /etc/docker-compose/docker-compose.tplを編集して、
  2. 変数の書き換えの定義などをtop directoryのMakefile内の.docker-compose.ymlあたりのcommandとして用意して、
  3. make dupすれば.docker-compose.ymlとか生成してcontainer起動するので、
  4. make dloginとかその他のcommand使って普通にdockerを使えばいい

というものなんだけど。ここで話したいのはそういう話しじゃなくてどうやって作っていったかの七転八倒なので(何故そっちを……)。

よし。

  1. Dockerfileを作った時の悲喜交々
  2. .docker-compose.ymlをいじっていった時の苦労
  3. その他

くらいの感じで話してみようか。

Dockerfileの作成

C++開発用のDockerfileの作成だけど、基本的にはgccとmakeとboostが入っていればいい。

と思ってたけどそういやgdbとかstraceとかvalgrindとかも欲しいな。この時点ではDockerでgdbとか動かせるのか? という疑問もあったけど(daemon作るつもりだったから……。つまり起動してからattacheしないと駄目でしょ? あれ、Dockerってそういうことできたっけ? 単純に一つのapplicationを起動させるだけなら出来るって知ってるけど、的な悩み)、まあそれはあとでDocker-Composeでいじる時に悩むことにする。

で、最終的に出来たのがこれ。

baseとしたimageはcentos7。

# RUN yum -y install gcc \
#              gcc-c++ \
#          automake \
#          make \
#          libtool \
#          cppunit \
#          cppunit-devel \
#          valgrind \
#          gdb \
#          strace

最初はこのcomment outされているところだけつくって、docker build -t test_gcc ./etc/docker-compose/images/gccとかcommand叩いて無事作れるか試していた。

で、yumだけなので動いて当然として、できればgccも最新のものとか使いたいなあという欲望が出てくる。

そしたらあるわけです。便利なものが。

最近はscl(Red Hat Software Collections )というものがあって、それで簡単に別のgcc環境が作れてしまう。すげーと感動しながら入れる。

RUN yum -y install gcc \
               gcc-c++ \
           automake \
           make \
           libtool \
           cppunit \
           cppunit-devel

RUN yum install -y centos-release-scl \
               centos-release-scl-rh
RUN yum install -y devtoolset-7-gcc \
               devtoolset-7-gcc-c++ \
           devtool \
           devtoolset-7-valgrind \
           devtoolset-7-strace devtoolset-7-gdb \
           devtoolset-7-gcc-gdb-plugin

yumでとりあえず最低限いりそうなものだけいれておいて、devtoolset-7-gccをいれる。

gccgcc-c++はいるっけ? libtoolも。まあいれとこう。<最低限とは何だったのか

これ開発環境だからこうだけど本番環境ならそもそもboostくらいしかいらない気がするのでちょっとcontainerの作り方がめんどいかもしれない。まあ今は開発環境のものだけなのでいいか。

あとはboostだけどこれはまあ仕方ないので素直にbuildした。

RUN yum -y install wget
ARG boost_version=1.66.0
ARG boost_file=boost_1_66_0
RUN cd /tmp \
    && scl enable devtoolset-7 bash \
    && wget https://dl.bintray.com/boostorg/release/${boost_version}/source/${boost_file}.tar.gz --no-check-certificate \
    && tar xfz ${boost_file}.tar.gz \
    && rm ${boost_file}.tar.gz \
    && cd ${boost_file} \
    && ./bootstrap.sh \
    && ./b2 --without-python --prefix=/usr -j 4 link=shared runtime-link=shared install \
    && cd .. \
    && rm -rf ${boost_file} \
    && ldconfig

これで終わり。開発環境となるdocker imageはこれで作れた。

Docker-Composeの設定

で、次はDocker-Compose用に.docker-compose.ymlを作成する。結果はこの通り。

今回作ったcontainerの意味するところは以下の通り。

Name Description
data busybox。hostの./src以下をmountするためのContainer。
gcc gccのbuild/実行用のContainer。data containerをvolumeとしてmountする。vmみたくloginしての利用も出来る。gdbなどを使うときのため。
build 上に同じく。ただしこちらはloginすることは想定していない。
server 生成したserver applicationを実行するための設定。本来ならこれは専用にcontainer作るべきな気がする。gccとかvalgrindとかいれてないやつ。

ちょっと京菜事をしているのはdataというcontainerをよそがmountしているという処理。

これはどういうことか言えば、複数のcontainerが同じdirectoryをmountしたりしたらとても面倒なことになりそうなので、hostのdirectoryをmountする作業は全部一つのcontainerに任せてしまいましょう、という話。

あとはdocker-composeでsetupすれば通る。

$ docker-compose -f .docker-compose.yml up -d data
$ docker-compose -f .docker-compose.yml up -d gcc

あとはよく使うcommandをmakefileにまとめて終わり。

他のserviceも立ち上げたい場合

他のserviceも立ち上げたい場合はこれ、./etc/以下にconfigとかいれておいて、.docker-compose.ymlに専用のcontainerを定義すればいい。

imageも別途作る必要があるけれど、gccの開発環境のDockerfileを参考に適当に作る感じになる。