LoginSignup
27
19

More than 3 years have passed since last update.

コンテナでC言語の開発環境を構築する

Last updated at Posted at 2019-06-25

この記事について

C言語の開発環境には様々な依存ライブラリをインストールする必要があります。そのため開発者それぞれの環境を統一するのが大変です。これまで環境を統一するためには、

  • 開発者全員が同じマシンの開発環境を使って開発
  • 開発環境構築手順書を作成し、配布する
  • 開発環境のVMイメージを配布する

のような面倒なことをする必要がありました。
でも、今はコンテナという便利な物があります。
筆者もこれまでAWSのEC2上に開発&試験環境を作り、開発者へ提供していました。現在はDockerfileやDockerイメージを提供しています。ここではDockerfileとイメージの作成し、その利用方法を説明します。

前提

Docker for Mac/Windowsなど,Dockerコンテナが動作する環境がインストール済みである事。あと、ほんの少しDockerやLinuxの知識が必要です。
尚、この記事ではmac上での作業内容を記載しています。Windowsで作業する場合はパス等、適宜読み替えてください。

ゴール

この記事では、DockerコンテナのCentOS上で次の事ができるようになります。

  1. viでC言語のソースが書ける
  2. gcc,makeを使って、C言語のプログラムがコンパイルできる
  3. コンパイル済みの実行ファイルが実行できる
  4. コンパイル済みの実行ファイルがgdbでデバッグできる
  5. (おまけ)java,pythonも使える

Dokerfile作成

dokerファイルはコンテナイメージを作るための設計図です。
コンテナを使う以前は、OSやライブラリ等のインストールを手作業で行っていました。その手順をメモする替わりにDockerfileに書いておけば、簡単に再現できます。
これぞまさしく Infrastructure as Code(IaC) の第一歩ですね。

まずイメージを作る場所を決める

まず、イメージを作る場所を決めます。そこにDockerfileを作成/配置します。

> cd ~/docker/

Dockerfile

完成版はこちら(Dockerfile)から
Dockerfileにいろいろ記載してきます。

ベースイメージ

好きなOSを選んでください。
ここでは開発環境としてCentOS 7を選びます。

From centos:7

ワーキングディレクトリ

インストール作業するディレクトリを指定します。

WORKDIR /root

モジュールのインスール

yum で好きなパッケージをインストールしてください。
C言語で開発するなら、yumのgroupinstallが便利です。イメージが大きくなりますが、開発環境なら問題ないでしょう。

RUN yum -y update && \
    yum -y groupinstall "Development Tools"

その他はご自由に!
こちら(Dockerfile)には、普通に使いそうなものを記載しています。

イメージへファイルの取り込み

ホストPCのファイルシステムからイメージ内へファイルを取り込みます。

COPY .bashrc /root/

今回はshell実行時に環境変数が設定された状態にしたいので、.bashrcをイメージに追加しています。
必要なファイルがあったら
 COPY [ホストPCのファイル] [Dockerイメージ内の位置]
で追加してください。

Dockerイメージ作成

Dockerファイルのあるディレクトリ(ここでは ~/docker/)に移動してビルドします。

> cd ~/docker/
> docker build -t c_dev_env .

ちょっと時間がかかります。

> docker images
REPOSITORY                TAG                 IMAGE ID            CREATED             SIZE
c_dev_env                 latest              aa8cc7f4372f        About an hour ago   1.45GB

これでDockerイメージ「c_dev_env」の完成です。

参考
DockerHubに登録(push)するためには、タグ(-tオプション)に[organization]を付加する必要があります。
docker build -t [organization]/c_dev_env .

Dockerコンテナ実行

この記事で一番重要な内容部分です。gdbコマンドがシステムコールを使用しているため、適切なオプションを付けないと実行できません。

docker run -it --name "my_dev_env" --cap-add=SYS_PTRACE --security-opt="seccomp=unconfined" c_dev_env /bin/bash

オプション、パラメタの説明

オプション/パラメタ 説明
-i (--interactive)stdinを使用する
-t ttyを有効にする          
--name 名前をつける。ここでは"my_dev_env"
--cap-add=SYS_PTRACE Linux Capability ptrace()システムコールを許可。 (参考)Man page of Capabilities
--security-opt="seccomp=unconfined" seccompという仕組みでもシステムコールが制限されているため、それを回避。(参考)seccompプロファイルを使ってdockerのシステムコールを制御
パラメタ1 イメージ名。ここでは c_dev_env を指定
パラメタ2 実行コマンド。ここでは/bin/bash を指定

-v [ホストPCのディレクトリ]:[コンテナのディレクトリ] で、マウントしておくと便利です。ホストPCの慣れたエディタで開発できます。

> docker run -it --name "my_dev_env" --cap-add=SYS_PTRACE --security-opt="seccomp=unconfined" c_dev /bin/bash
bash-4.2# cat /etc/redhat-release
CentOS Linux release 7.6.1810 (Core)
bash-4.2#

これで実行環境が完成しました。

プログラム作成&実行

それでは簡単なプログラムを作って、実行してみましょう。
Dockerイメージ内 /root/sampleの下へ

bash-4.2# cd /root
bash-4.2# mkdir sample
bash-4.2# cd sample
bash-4.2# vi hello.c

プログラム作成 hello.c

hello.c
#include <stdio.h>

int main(void)
{
  int sum = 0;
  sum++;
  printf("Hello, World!\n");
  printf("sum = %d\n", sum );
  return 0;
}

そしてコンパイル
gcc -g -o hello hello.c
-g:デバッグオプションを忘れずに!

bash-4.2# gcc -g -o hello hello.c
bash-4.2# ls -la
total 24
drwxr-xr-x 2 root root 4096 Jun 23 14:24 .
dr-xr-x--- 1 root root 4096 Jun 23 14:23 ..
-rwxr-xr-x 1 root root 9528 Jun 23 14:24 hello
-rw-r--r-- 1 root root  136 Jun 23 14:24 hello.c
bash-4.2# ./hello
Hello, World!
sum = 1

ちゃんと実行できています。

デバッグ

今度は、gdbでデバッグしてみましょう


bash-4.2# gdb hello
GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-114.el7
〜 省略 〜
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /root/sample/hello...done.
(gdb) 

エラーもなくプロンプトが出てきました。
続いて、ブレークポイント設定&ステップ実行

(gdb) l <---リスト表示
1   #include <stdio.h>
2
3   int main(void)
4   {
5     int sum = 0;
6     sum++;
7     printf("Hello, World!\n");
8     printf("sum = %d\n", sum );
9     return 0;
10  }
(gdb) b 6  <---6行目にブレークポイント設定
Breakpoint 1 at 0x40056c: file hello.c, line 6.
(gdb) r   <---実行
Starting program: /root/sample/hello

Breakpoint 1, main () at hello.c:6
6     sum++;  <---ブレークポイントで止まった!
Missing separate debuginfos, use: debuginfo-install glibc-2.17-260.el7_6.5.x86_64
(gdb) n   <---ステップ実行
7     printf("Hello, World!\n");
(gdb) p sum <---変数内容表示
$2 = 1

ブレークポイント設定、ステップ実行問題なくできています。

Dockerコンテナから抜ける

最後に、DockerコンテナのLinuxから抜けるには Ctrl+p ,Ctrl+qです。
もう一度つなぐ時は、 docker attach [タグ名]

> docker attach my_dev_env
bash-4.2#

まとめ

Infrastructure as Code(IaC) は大規模システムの環境構築、特にパブリッククラウドやコンテナオーケストレーション環境では必須の技術要素です。しかし、こんな身近な環境でも体感できる事に、少し感動しました。(当たり前なのですが)

  • インストール手順書をDockerfileで書く
  • 環境構築手順書をPlaybookに書く

これもInfrastructure as Code(IaC)の重要な要素であり、これだけでもトイル(
SRE サイトリライアビリティエンジニアリング 5章)
を確実に減らすとことができる気がします。ただし、Dockerfile職人とPlaybook職人による属人化には気をつけて。

27
19
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
27
19