Dockerで開発環境をきれいに管理したい

5/21に技術書典という技術書の同人誌即売会に行ってきました。そこでUEFIの本を購入したのでさっそく開発環境を作って勉強してみようと思ったのですが、お絵かきソフトのkritaをビルドしたときと同じで環境を汚したくない!というのがあり、今回もdockerを使って環境を作ってみることにしました。kritaのときは既存のDockerfileからイメージをビルドできてすぐに環境が作れました。dockerの簡単な操作はこのときに多少知れたので、今回はDockerfileを書くところからやってみたいと思います。

Dockerfile

  • 概要
    • 開発に必要となるソフトウェアのインストールを行い、開発用のユーザーを用意します。ユーザーを用意しないとコンテナのubuntuにログインしたときにルートで入ってしまうからです。
FROM ubuntu:22.04
RUN apt -y update
RUN apt -y upgrade
RUN apt -y install make
RUN apt -y install git
〜UEFI開発に必要なものを同じようにインストールする〜
RUN useradd -m devuser && echo "devuser:パスワード"|chpasswd && echo "devuser ALL=(ALL) ALL" >> /etc/sudoers
USER devuser
RUN cd /home/devuser/ && git clone UEFI開発に必要なソースコードのURL && cd クローンしたソースコードのディレクトリ && make && mkdir 作業用ディレクトリ
  • FROM
    • 自分が使うために必要な基本的なものが揃っているイメージをここに書くみたい。
      このイメージに対して色々加えていくことで目的のイメージを作る。
      OSが指定されることが多い。
      ダウンロードしてきていないイメージは、自動的にダウンロードされる。
  • RUN
    • レイヤーの概念があり、RUNすると結果がコミットされてレイヤーとして積まれるっぽい。(この仕組みのおかげでやり直しがしやすいようだ)RUNの中の書き方には2通りあって、今回の記法はシェル形式。
      RUNが実行される場所は/なのでcdを指定するときは注意する。RUNが指定されると、前の行のRUNでcdしていてもディレクトリは/に戻る。そのためcdで移動したら&&で繋いで続けて実行している。

Dockerイメージの作成

$ docker build -t イメージ名 .
  • Dockerfileを作ったディレクトリで実行
  • ついつい何かファイルが作成されるのかと思ってディレクトリ内を確認してしまうのですが、出来たイメージはdocker image lsコマンドを使って確認

コンテナを新しく作って起動

$ sudo docker run -it -d イメージ名
  • オプションで–nameを指定すると、コンテナ名を指定できる。今回は特に指定しなかった。-dを指定するとコンテナにいきなり入らずにバックグラウンドで実行された状態になる。

  • オプションを指定せずにdocker run イメージ名と指定すると、立ち上がった後にすぐ停止する。このときdocker psコマンドで見てみても何も表示されないが、オプションの-aを付けると停止中のコンテナも表示されるので、その中に今実行したコンテナを見つけられる。
    この停止中のコンテナをdocker startで起動しようとすると、またすぐ停止してしまう。これはrunのときにオプションを指定していなかったので、このコンテナが普段ターミナルでコマンド打ってやりとりするような対話型のコンテナとして作成されなかったからのようだ。

  • ちょっとお試しで標準入力を開くためのオプションiを指定しなかったら、ログインしたときに入力を受け付けなくなった。

📕docker create

📕docker run -it で学ぶ tty とか標準入出力とかファイルディスクリプタとか

コンテナのubuntuにログインする

今回作った開発環境には、開発用のユーザーを作成したので以下のように接続します。

$ sudo docker container exec -it --user=ユーザー名 コンテナ名 /bin/bash

docker attachを使う方法もあったのですが、こちらで。
attachはコンテナで動いているプロセス(PID=1)に接続するらしい。以下のようにコンテナ側のプロセスを確認してみるとPID=1にbashと書いてあるので、attachしたときはこれに接続されると思われる。PID=40はexecで今接続したやつかな。で、attachで接続したときにexitで抜けるとこのプロセス自体も終了するのでコンテナも停止する。

devuser@6540825db159:/$ ps -A
    PID TTY          TIME CMD
      1 pts/0    00:00:00 bash
     40 pts/1    00:00:00 bash
     52 pts/1    00:00:00 ps

execのほうは新しいbashプロセスを立ち上げたものに繋ぎに行くけど、attachの方は既にあるプロセスに繋ぎに行くという違いがある。

これで目的の環境はできました!dockerにしたことで特有の問題が出てきたら嫌だな…。またそのときに考えよう🙄

よく使うコマンド

Dockerを起動/停止

$ sudo systemctl start docker
$ sudo systemctl stop docker.socket

イメージの一覧

$ docker image ls

コンテナ一覧

$ docker ps

オプションで-aを指定すると、停止中のコンテナも表示する。

コンテナを起動/停止

runで既に作ってあるコンテナを起動する。

$ docker start コンテナID/名
$ docker stop コンテナID/名

コンテナを削除

$ docker rm コンテナID/名

参考

Docker exec/attachコマンド
Docker入門(第四回)~Dockerfileについて~
Docker base image, an overview - IBM
Dockerfileによるビルド