🐳

技術書をハンズオンするための最低限の環境をdockerで作る[Ubuntu]!!

2021/04/15に公開

こんにちは、あと一年で社会人になるので今のうちにいろいろ勉強しているhagaahiroです!
最近の趣味は技術書を積むことです。

最近の思いとして、
「dockerとかの仕組みを低レイヤから理解したいからLinux系の本を買ってハンズオンしてるんだけど、結局環境がubuntuがほとんど
dockerで環境作ってからやることが多い。。。😂」
というのがあります。

技術書にはハンズオンがついているものも多くあります。
ただ、そのハンズオンの環境構築に詰まることも往々にしてあります。

自分はMacOSを使用しているのですが、技術書はUbuntuを使われていることが非常に多いです。
vagrantを立ち上げるのも時間がかかるので、ちょっとめんどくさいということもあります。

そこでこの記事では、
さっさと技術書に書いてある環境構築を終わらせて、本の本題に入りたい人向けに、dockerを使った環境構築方法
をメモがてら書いていきます。

ゴールとしては、技術書に書いてある環境をdockerで気軽にさくっと構築できるようになることとします。

なお、「そもそもコンテナとは」「dockerとは」のような話は他の記事に譲ることとします。
記事の最後に参考にさせていただいた記事リストも載せておきます。

前提(私の環境)

  • MacOSを使用
  • dockerアプリはダウンロード済み

この記事では例として『[試して理解]Linuxのしくみ ~実験と図解で学ぶOSとハードウェアの基礎知識』で使用される環境を作成していきます。

dockerを使って環境構築をしてみる

今回は下記のような環境を作成することをゴールとします。

  • Ubuntuを使用する
  • binutils、buildessential、sysstatをパッケージとして入れる
  • straceコマンド、macコマンドを使えるようにする

ここまでをやります。
最終的にはとても簡単なファイルになります。

Dockerfileからdocker imageを作成

まずはDockerfileからdocker imageを作成してみようと思います。
Dockerfile -> build -> docker imageというのが流れになります。

docker imageとは

docker imageとはdockerコンテナを立ち上げる元となるものです。
詳しくはこちらの記事を!

Dockerfileとは

Dockerfileとはdocker imageの設計図となるものです。
このファイルに記述した情報を元にimageを作成します。

下記の例のようにINSTRUCTION argumentsの形で記述します。

FROM ubuntu:18.04
COPY . /app
RUN make /app
CMD python /app/app.py

ではここまでを実際に自分の環境でやってみましょう。dockerアプリ自体はダウンロードしておいて下さい。

$ mkdir linux-docker-practice # 任意のディレクトリを作成
$ cd linux-docker-practice
$ touch Dockerfile # Dockerfileを作成

実際にDockerfileを開いて、コードを記述します。
今回だと下記のようなコードが出来上がります。

FROM ubuntu:latest
RUN apt-get update && \
    apt-get install git binutils build-essential \
    sysstat strace man -y \
    && mkdir /workdir

このファイルは下記のことをしています。

  • ベースイメージとしてUbuntuの最新版を指定
  • apt-getでパッケージをインストール
    • git, binutils, build-essential, sysstat, strace, manをインストールしています。
    • ちなみにMacではhomebrewがよく使われます。
  • -yはinstall中に聞かれる質問を全てYesで回答するために指定
  • mkdir /workdirでリモートコンテナ内にworkdirというディレクトリを作成
    • 後述する「ホストをコンテナにマウント」するためにやっています。

コードの内容を見ていきましょう。

FROM

まず、ファイルの1行目にFROMという記述があり、ubuntu:latestと指定されています。
FROMはベースイメージを指定するものです。
ベースイメージとは、イメージレイヤーの一番下になるものです。
ここが基本となって後続の処理が走ることになります。

例えば、Linuxコマンドを実行するには当然ながらLinux(Linuxの種類としてUbuntuなどがある)が必要です。
apt-gettouchなどのLinuxコマンドを指定するにはUbuntuが入っている必要があります。

MacOSだとapt-getは使えません。
FROMはDockerfileの1行目に記述するようにしましょう。

RUN

RUNは指定したアクションをimageが実行するためのものです。

RUNごとにレイヤーが作られるので、基本的には分けて書くのではなく、つなげて書く方が良いです。
レイヤーが増えてイメージが大きくなるとそれだけ非効率なコンテナになってしまいます。

例えば、下記の二種類の書き方だと後者の方が良いです。

 # NG
 FROM ubuntu:latest
 RUN touch test
 RUN echo 'ohayo' > test
 RUN cat test
 
 # OK
 FROM ubuntu:latest
 RUN touch test && echo 'ohayo' > test \
 cat test

&&でコマンドをつなぐことができます。
\で改行ができます。


ここまででざっくりとDockerfileの中身について解説しました。

では、作成したDockerfileをビルドしてdocker imageを作成しましょう。

 $ cd linux-docker-practice # Dockerfileがあるディレクトリに移動
 $ docker build -t ubuntu-latest . # ubuntu-imageという名前をつけてカレンとディレクトでビルド
 $ docker images

docker build <Dockerfileがあるディレクトリ>とすることでdocker imageを作成できます。
この時に、-t <name> とすることでdocker imageに名前をつけて管理することができます。

実行してみます。

[~/Desktop/tameshite-linux] $ docker build -t ubuntu-latest .
[+] Building 4.0s (7/7) FINISHED                                                                                   
 => [internal] load build definition from Dockerfile                                                          0.0s
 => => transferring dockerfile: 37B                                                                           0.0s
 => [internal] load .dockerignore                                                                             0.0s
 => => transferring context: 2B                                                                               0.0s
 => [internal] load metadata for docker.io/library/ubuntu:latest                                              3.8s
 => [auth] library/ubuntu:pull token for registry-1.docker.io                                                 0.0s
 => [1/2] FROM docker.io/library/ubuntu:latest@sha256:3c9c713e0979e9bd6061ed52ac1e9e1f246c9495aa063619d9d695  0.0s
 => CACHED [2/2] RUN apt-get update &&     apt-get install git binutils build-essential     sysstat strace m  0.0s
 => exporting to image                                                                                        0.0s
 => => exporting layers                                                                                       0.0s
 => => writing image sha256:fd94075efd8f2f56454f55c953b2a35068e989c5846c9f657650cc326140e5df                  0.0s
 => => naming to docker.io/library/ubuntu-latest                                                              0.0s
[~/Desktop/tameshite-linux]

docker imagesで作成したイメージを確認してみましょう。

[~/Desktop/tameshite-linux] $ docker images
REPOSITORY        TAG       IMAGE ID       CREATED       SIZE
ubuntu-latest     latest    fd94075efd8f   1 hours ago   381MB

さてここまでで、Dockerfileを作成し、そのDockerfileからdocker imageを構築することができました。
ただしこのままでは実際にコードを動かしたりできないので、実行環境であるコンテナを起動する必要があります。

docker imageからコンテナを立ち上げる

まずはコードを実行していきましょう。

$ docker run -it -v ~/Desktop/linux-docker-practice:/workdir ubuntu-latest bash
root@d374440bc52b:/# cd workdir  
root@d374440bc52b:/workdir# ls
Dockerfile

ここまでで下記のことをしました。

  • コンテナを作成し、起動。ホストのフォルダをコンテナにマウント
  • コンテナにアクセスし、workdirに移動
  • lsコマンドを実行し、Dockerfileがあることを確認

コマンドを確認していきましょう。
$ docker run -it -v <hostのディレクトリpath>:<コンテナのファルパス> <name or image id> bash

  • docker run
    • コンテナを作成し、起動する
  • -i
    • キーボードからの入力をホストからコンテナに繋ぐことができる。これを指定しないとコンテナアクセス後にcdとかしても動かない
  • -t
    • 出力を整理する。補完なども効くようになる
    • -itとしてにdocker run時にはほぼ全ての場合で指定しておくと良い
  • -v <hostのディレクトリpath>:<コンテナのファルパス>
    • 立ち上げたコンテナ内から自分のPC上にあるフォルダにアクセスできるようにする
    • :前後は順不同なので注意

ここでやっているようにわざわざホストのファイルにアクセスしなくても、コンテナ内でフォルダを作ればいいじゃんということになりますよね。

  • コンテナ内にファイルをおくと、コンテナが大きくなってしまう
  • コードはホストに置いておいて、実行する時にコンテナを使うのが良い

という理由があるのでマウントをするようにしています。

さてこれで環境構築が完了しました。
Macだとcommand not foundとなるようなsarstraceも使えるようになっていると思います。

まとめ

私自身、dockerをしっかりと使ったことがないので、説明が不十分だったりする箇所もあるかと思います。
気になる点がございましたら、コメント欄で教えていただけると幸いです🙇‍♀️

これで心置きなく、技術書のハンズオンができますね!!
ここまで読んでいただきありがとうございました!

参考にさせていただいた記事たち

Discussion