Back to tech

Docker で c++ をビルドする環境を作ってみた

4 min read
Table of Contents

Docker をお仕事で使うということで勉強してみました.

Docker の概要はググればいくらでもでてくるので,私が勉強がてらやっていた Dokcer で C++ の環境を構築し,実行してみるところまでを記載していきます.

内容としては,はじめにコンテナ内でビルド環境を構築後にビルド行い,その後 DockerFile を作成し再度ビルド行ってみる.

最後に Docker-compose を使用してビルドしてみることにしてみます.

[affi id=1]

参考にした書籍

オライリーの 鯨本 を参考にして勉強をしました.

Docker の概要が丁寧にまとまっており,Docker が必要になった背景や仕組みが丁寧に記載されておりました.

しかし一方で,サンプルの記載が古いため実行できないものや索引のページのミスがあったりと,ググる力がないと大変読みづらい本だと感じました.

Docker で C++ の環境をつくってみる

あくまで勉強として構築した記録です.

すぐに C++ の環境使えないの?という人はmadduci/docker-alpine-cpp イメージを pull してくればすぐに使えると思います.(未確認)

※ Docker のインストールしている前提で進めていきます.

今回作成したソースコードは github に上げています

GitHub - Momijinn/training-docker
github.com
image

ビルド対象のソースコードを準備する

ファイル構成は以下のようにしました.

app にビルド対象のソースコードを入れていくようにしていきます.

training-docker/
└── app

C++ のソースコード (main.cc) と makefile は以下のように記載

main.cc https://github.com/Momijinn/training-docker/blob/master/app/main.cc

makefile https://github.com/Momijinn/training-docker/blob/master/app/makefile

ディレクトリ構成は以下のようになります.

training-docker/
└── app
    ├── main.cc
    └── makefile

コンテナを作成して C++ をビルドをしてみる

DockerFile を作る前にコンテナ内でC++ がビルドできるかやってみます.

ベースは軽量と定評がある alpine Linux を使用してみます.

cd training-docker
docker run -it --name myalpine -v $(PWD)/app:/app alpine:3.12.0 /bin/sh

$(PWD) を使うことで current path を取得できる. ※ -v を使うことでホストとバインドする.ソースコードはホストと共有したいためこのようにする. ※ —name を使うことで コンテナ名前をつける.(つけないと適当な名前になる) 詳細は書籍や公式サイトを参考

docker run を行うと コンテナ内に入れることができます.

コンテナ内で C++ をビルドするためにパッケージをインストールしていきます.

apk update
apk install g++=9.3.0-r2 make=4.3-r0

※ パッケージをインストールするときはバージョンを指定してインストールすることで,どの環境でも同じコンテナを作れるようにするため.

上記のコマンドで C++ をインストールする環境は整いました.

実際に Docker 内でビルドして実行してみます.

“Hello World” が出れば成功です.

/ # cd app/
/app # make
g++ -o main main.cc
/app # ./main
Hello World

Tips: コンテナから出る・再度コンテナ内に入る

  • コンテナからでる コンテナ内で exit

    exit
  • 再度コンテナ内に入る

    $ docker exec -it CONTAINER_NAME /bin/sh
    e.g. ) $ docker exec -it myalpine /bin/sh

    ※ docker run をすると新たにコンテナが生成される

dockerfile をつくる

上記で コンテナ内で C++ をビルドする環境を作ることができました.

しかし,新しく C++ 環境をつくるためにコンテナを作ってパッケージを入れて実行する手順を踏むのはすごくめんどい & 別のPC にセットアップするのもめんどい です.

なので,イメージ化してしまい,すぐに環境をセットアップできるようにしてしまおうというのが dockerfile です.

dockerfile の作成は先ほども書いましたが,コンテナを作成して C++ をビルドをしてみる ことと同じ順番通りに作成 & 実行できるよう作っています.

dockerfile https://github.com/Momijinn/training-docker/blob/master/dockerfile

1. alpine linux をベースに作成
2. 作成者を記載
3. 必要なパッケージをインストール
4. docker run した時に実行させるシェルスクリプトをコンテナ中にコピー
5. 実行権限をつける
6. docker run をするときに実行させるシェルを指定

※ dockerfile 独自のコマンドは公式を参照

docker run をした時に make も実行してほしいので ENTORYPOINT に シェルスクリプトを実行するようにしています.

ENTRYPOINT [ "./opt/docker-entorypoint.sh" ]

シェルスクリプトは以下のように作りました. https://github.com/Momijinn/training-docker/blob/master/startup/docker-entorypoint.sh

docker run に引数がなければ make を行い, clean という文字列が渡されたらビルドしたビルドファイルを削除. 引数に応じてやることを変えたいので make を渡すのではなく, シェルスクリプト内で make をするようにしました.

ここまでのディレクトリは以下

training-docker/
├── app
│   ├── main.cc
│   └── makefile
├── dockerfile
└── startup
    └── docker-entorypoint.sh

Docker build してみる

dockerfile を作れたので docker イメージをつくためにビルドします.

dockerfile があるディレクトリで docker build します.

$ cd training-docker
$ docker build -t traning-docker .
~~
Successfully built 2d44ac1d33f7
Successfully tagged traning-docker:latest

-t で Docker イメージの名前を決めることができる

docker images コマンドを叩いて作成したイメージがあるか確認します.

traning-docker があることを確認.

$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
traning-docker      latest              2d44ac1d33f7        40 seconds ago      205MB
alpine              3.12.0              a24bb4013296        2 months ago        5.57MB

お次に イメージからコンテナを作成し,C++ をビルドしてみます.

$ docker run -it --rm --name myalpine -v $(PWD)/app:/app traning-docker
make
g++ -o main main.cc

—rm で スクリプトが終了後コンテナが自動で削除される

ホスト側で ビルドファイルが生成されているかを確認.

main というビルドファイルができています.

$ cd training-docker
$ tree app
app/
├── main
├── main.cc
└── makefile

ビルドされたファイルを実行して削除してみます.

$ docker run -it --rm --name myalpine -v $(PWD)/app:/app traning-docker exec
Hello World

$ docker run -it --rm --name myalpine -v $(PWD)/app:/app traning-docker clean
make clean
rm -f main

$ cd training-docker # host 側で確認
$ tree app
app/
├── main.cc
└── makefile

tips: docker run した時に ENTORYPOINT を実行せずにコンテナ内に入る場合

docker run オプションにて —entrypoint ” を渡す.

# e.g.)
$ docker run --rm --entrypoint '' -it --name myalpine -v $(PWD)/app:/app traning-docker /bin/sh
/ #

Docker-compose を使ってみる

もう一手間加えてみます.

docker builddocker run するときにオプションを付けますが,毎回つけるがめんどい & 覚えてられないという事態があると思います.

そのときに使うと便利なのが docker-compose です. ※ docker-compose はオプション覚えてられないから使うというよりは,複数の docker を動かす時に使われることが多いそうです.

docker-compose.yml を作成 https://github.com/Momijinn/training-docker/blob/master/docker-compose.yml

ディレクトリ構成は以下

$ tree training-docker/
training-docker/
├── app
│   ├── main.cc
│   └── makefile
├── docker-compose.yml
├── dockerfile
└── startup
    └── docker-entorypoint.sh

C++ をビルド & 実行

$ cd training-docker/
$ docker-compose run --rm myalpine
make
g++ -o main main.cc
$ docker-compose run --rm myalpine exec
Hello World

その他 tips

docker コンテナ全削除

docker rm $(docker ps -aq)

docker イメージ全削除

$ docker rmi $(docker images -aq)
# 強制削除するときはオプションに -f をつける

まとめ

Docker でいちから C++ を構築する方法をつらつらと書いていきました.

ホットな技術であり,いい機会に学ぶことができたと思います.

docker-compose があまり理解し切れていないので深掘りできたらと思います.

docker をつかうことで「あなたの環境では動くけど私の環境ではうごかない.どうして!」問題がなくなる素晴らしい技術なのでどんどん使っていきたいです.