Dockerコンテナのライフサイクル

モチベーション

  • Dockerのライフサイクルについてまとめておきたい
  • Dockerfileの書き方についてまとめておきたい
  • docker-composeについてまとめておきたい

Dockerのライフサイクル

  • docker runで,Dockerイメージを元にコンテナを起動する.
  • docker stopで,コンテナを停止する.
  • docker commitで,停止中のコンテナを新たなDockerイメージとしてとっておく.
  • docker save/loadで,Dockerイメージを持ち運ぶ.
  • docker startで,停止中のコンテナを再開する.
  • docker rmで,停止中のコンテナを破棄する.
  • docker rmiで,Dockerイメージを破棄する.

Dockerイメージを用意する

  • Dockerfileの書き方
  • docker build -t <image name>:<tag> <Dockerfileがあるディレクトリ>によりDockerイメージがつくられる
    • <tag>にはimageのversionを設定するのが一般的.<tag>を省略した場合はlatestとされる.
  • docker pull <image name>でDockerイメージをもってくることができる.
    • DockerイメージはDocker Hubにて検索できる.
  • docker imagesで手元にあるDockerイメージ一覧を表示する.
    • docker images -qにより,DockerイメージID一覧を表示する.

Dockerイメージを元に,コンテナを立ち上げる

  • docker run -it --name <container name> <image name>:<tag> <command>
    • <image name>:<tag>から<container name>という名前のコンテナを立ち上げ,コンテナ内で<command>を実行する.
    • -iはホストからコンテナへの標準入力を繋げるためのもの.-tはコンテナからホストへの標準出力を繋げるためのもの.
    • -hオプションによって,ホスト名を指定できる.
    • -dオプションによって,コンテナをバックグラウンドで実行できる.
    • -p <host>:<container>オプションによって,ホストのポートとコンテナのポートをつなげる.この時,iptablesが書き換えられ,ホスト側のポートがWANに曝されるので注意.
      • -pでなく,--expose <port>フラグを指定すると,リンクしたコンテナから<container name>:<exposed port>でアクセスすることができる.また,iptablesは変更されない.
    • --rmフラグによって,コンテナがstopしたあとはコンテナを削除するようにする.
    • --privilegedフラグによって,コンテナ内からホストのデバイスにアクセスすることができる.セキュリティには注意する.
      • --deviceフラグや--cap-addフラグによってデバイス単位で細かくアクセス権限を制御することができる.
    • --link <container>:<nickname>を指定することで,<container>へアクセスする際のホスト名として利用できる.
      • 例えば,hogeという名前のコンテナが立ち上がっている環境で,--link hoge:hgを指定して新たなコンテナを立ち上げたとすると,そのコンテナからはcurl http://hogeというような形でアクセスすることができる.
    • Dockerイメージによっては,ずっと起動するものもあれば,<command>を一発実行してstopするものもある.
      • <command>/bin/shを指定し,コンテナ内にshを立ち上げることで,コンテナを立ち上げたままにしておくことが多い.
  • docker ps
    • 起動中のコンテナ一覧を表示する
  • docker attach <container>
    • コンテナにアタッチする.アタッチ後の振る舞いはDockerイメージによって異なり,コンテナの標準入出力が可能になる場合もあれば,何も起きない場合もある.
    • アタッチしている状態で,ctrl+pctrl+qすると,コンテナからデタッチすることができる.
  • docker exec -it <container> <command>
    • 起動中のコンテナにコマンドを流し込むことができる.
    • <command>/bin/shを指定してコンテナ内にシェルを立ち上げることで,コンテナ内で作業することができる.

DockerコンテナのPID=1問題

docker runで指定した<commnad>は,PID=1のプロセスとして実行される.PID=1なプロセスはカーネルから特別扱いされるため,プロセス自体がシグナルをハンドルするように実装されていなければ,シグナルは無視されてしまう.

例えば,docker kill -s TERM <container>を実行することで,PID=1のプロセスにSIGTERMを投げることができるが,PID=1のプロセスのシグナルのハンドルの仕方によって振る舞いが異なる.

PID=1のプロセスがシグナルをハンドルするように実装するのもよいが,プロセスがPID=1以外で実行されれば,シグナルを素直に受け付けるので,<command>で指定したプロセスをPID=1以外にするためには,docker runを実行する際に,--initオプションを指定すると良い.

# docker run -it centos bash
[root@a31d57ca765c /]# ps -aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  1.5  0.1  12020  3348 pts/0    Ss   13:38   0:00 bash   <======== `bash`がPID=1で実行されている
root        14  0.0  0.1  47508  3520 pts/0    R+   13:38   0:00 ps -aux

# docker run -it --init centos bash
[root@52ec324240f8 /]# ps -axu
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  1.0  0.0    996     4 pts/0    Ss   13:39   0:00 /sbin/docker-init -- bash
root         7  0.0  0.1  12020  3336 pts/0    S    13:39   0:00 bash   <======== `bash`がPID=1以外で実行されている
root        16  0.0  0.1  44596  3388 pts/0    R+   13:39   0:00 ps -axu

起動中のコンテナを停止させる

  • docker stop <container>
    • <container>を停止する.
  • docker ps -a
    • 起動中または停止しているコンテナの一覧を表示する.
    • docker ps -a -qで,コンテナIDの一覧を表示する.

停止したコンテナを立ち上げる

  • docker start <container>

コンテナをrestartさせる

  • docker restart <container name>で,docker stopdocker startをまとめて実行してくれる,

停止中のコンテナをDockerイメージとして保存する

  • docker commit <container> <image name>:<new tag>
    • 停止中の<container>から,<image name>:<new tag>というDockerイメージを作成する.

Dockerイメージをtarで固めて持ち運ぶ

  • docker save <image name>:<tag> > <filename><filename><image name>:<tag>を書き出す
  • docker load < <filename>で読み込む
  • docker imagesでイメージが読み込まれたことを確認
  • docker run -it <filename>

停止しているコンテナを破棄する

  • docker rm <container>
    • 停止中のコンテナは,いつでも再開できるようにキャッシュされてるので,使わなくなったコンテナはdocker rmで破棄するようにする.
    • docker rm -fで強制破棄.
    • docker rm -f 'docker ps -a -q'により,すべての停止中のコンテナを強制破棄することができる.

ローカルのDockerイメージを破棄する

  • docker rmi <image>
    • docker rmi 'docker images -q'により,全てのDockerイメージを破棄する.

コンテナとホスト間でファイルをコピーする

  • docker cp <container>:<source@container> <target@host>
    • コンテナからホストにファイルをコピーする
  • docker cp <source@host> <container>:<target@container>
    • ホストからコンテナにファイルをコピーする

コンテナ内でstdout/stderrされたものを外部から見る

  • docker logs <container>
    • -fオプションでリアルタイムで表示する
    • ログ自体は/var/lib/docker/containers/<container id>/<container id>-json.logにある

ロギング情報の確認

  • docker info --format '{{.LoggingDriver}}'
    • 現在設定しているロギングドライバーを確認する
  • docker inspect -f "{{.LogPath}}" <container name>
    • あるコンテナのstdout/stderr出力を保存している先を確認する

Docker for Mac

Linuxでは,Dockerエンジンをホスト上で直接実行しているが,Docker for Macでは,Mac上にVMを立ち上げてその上でDockerエンジンを実行している. 例えば,docker volume lsでvolume名を取得し,そのvolumeがmountされている場所をdocker volume inspect <volume name>で確認すると,以下のようなMountpointを取得することができる.ただし,MountpointはMac上には存在せず,VMからみたパスである.

$ docker volume ls
DRIVER    VOLUME NAME
local     xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
...
$ docker volume inspect xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
[
    {
        "CreatedAt": "2019-12-21T05:10:05Z",
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/var/lib/docker/volumes/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/_data",
        "Name": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
        "Options": null,
        "Scope": "local"
    }
]

Dockerfileの書き方

Dockerfileとは,docker buildのための手順書のようなもの.Dockerfileを元にオリジナルのDockerイメージをつくることができる.

FROM nginx:latest
ENV HOGE FUGA
ARG AHO=DEFAULT
RUN apt-get update && \
    apt-get install -y certbot python-certbot-nginx && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/* && \
    ln -sf  /usr/share/zoneinfo/Asia/Tokyo /etc/localtime && \
    echo $AHO
WORKDIR /workspace
ADD nginx.conf /etc/nginx/
ADD default.conf /etc/nginx/conf.d/
EXPOSE 80 443
  • FROMでベースとなるDockerイメージを指定する
    • DockerイメージはDocker Hubにて検索できる.自分でつくったDockerイメージを指定することも可能.
    • <tag>を指定しない場合はlatestなイメージをもってきてくれる.
  • ENVで環境変数を設定する
    • RUN export HOGE=FUGAとしてもコンテナ内の環境変数には反映されない.ENV HOGE FUGAまたはENV HOGE=FUGAとする必要がある.
  • ARGで指定した変数は,docker buildコマンドの--build-argで任意に変更することができる
    • 例えば--build-arg AHO=TESTを指定すると,RUNecho $AHOが指定されてるので,build時にTESTと表示される.--build-argを指定しない場合はDEFAULTと表示される.
  • RUNにコンテナで実行したいコマンドを指定する
  • WORKDIRでホストと共有するディレクトリを設定する
  • ADD <src> <dest>でホストの<src>ファイルをコンテナ内の<dest>にコピーする
  • EXPOSEでコンテナの特定のポートを開けておく.docker run -p時にホストのポートとコンテナのポートを紐付けることでアクセス可能になる.
  • より細かいことはDockerfile リファレンスを参照する.

docker-compose.ymlでコンテナを複数立ち上げる

複数のコンテナをまとめて立ち上げたいときは,docker-composeを使う.

docker-compose.ymlを書く

version: '3'
services:
  nginx:
    image: nginx:latest
    ports:
      - 8080:80
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf
      - ./www/html:/var/www/html
    depends_on:
      - php

  php:
    build: 
      context: ./php
      args:
        - TZ=${TZ}
    container_name: php-fpm
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"
    volumes:
      - ./www/html:/var/www/html
    environment:
      - DB_CONNECTION=mysql
      - DB_HOST=db
      - DB_DATABASE=${DB_NAME}
      - DB_USERNAME=${DB_USER}
      - DB_PASSWORD=${DB_PASS}
      - TZ=${TZ}
    depends_on:
      - db

  db:
    image: mysql:5.7
    expose:
      - 9999
    volumes:
      - ./mysql/data:/var/lib/mysql
      - ./mysql/my.cnf:/etc/mysql/conf.d/my.cnf
    environment:
      - MYSQL_DATABASE=${DB_NAME}
      - MYSQL_USER=${DB_USER}
      - MYSQL_PASSWORD=${DB_PASS}
      - MYSQL_ROOT_PASSWORD=${DB_PASS}
      - TZ=${TZ}
  • docker-compose.yml内の${XXX}には,ホストの環境変数が適用される.
  • versionは2020年8月時点では3.詳しくは,Compose file version 3 reference
  • コンテナ毎にサービス名をつける.
  • buildまたはimageを指定する
    • DockerfileからDockerイメージを作成し,コンテナを立ち上げたい場合は,buildcontextにDockerfileがあるディレクトリへのパスを指定する. buildimageの両方を指定した場合は,ビルドされたDockerイメージの名前がimageで指定したものになる.
    • Dockerイメージからコンテナを立ち上げたい場合は,image<image name>:<tag>を指定する.
    • argsで,DockerfileのARGに渡すものを指定できる.
  • container_nameに,任意のコンテナ名を指定する.
  • loggingに,コンテナのstdout/stderr出力の保存方法を指定する
    • driverには,json-fileの他,syslogなども指定できる
    • optionsにログローテートの設定を指定できる.
  • tty: trueにより,docker run-itオプションに相当する設定がされる.
  • volumesには<ホスト側のパス>:<コンテナ内のパス>を指定する.これにより,ホスト側のディレクトリがコンテナ内のディレクトリと共有される.
  • environmentには,コンテナ内の環境変数を指定する.
  • portsには<ホスト側のポート番号>:<DockerfileでEXPOSEしたポート番号>を指定する.iptablesが変更させるので,ホスト側のポートが外部に曝されるので注意.
  • exposeにポートを指定することで,リンクしたコンテナから<container name>:<exposed port>でアクセスすることができる.iptablesは変更しない.
  • linksには<サービス名>:<コンテナ内からみたサービスのホスト名>を指定する.
  • depends_onには,サービスの起動に必要な別のサービスを指定する.これにより,コンテナが起動する順序が保証される.depends_onを指定すると,linksを指定する必要はなさそう.
    • 起動する順序は保証されるが,そのコンテナがアクティブかどうかはdepends_onで保証されないので,wait-for-it.shなどで細かく制御する必要がある.
  • 詳しくはCompose ファイル・リファレンスを参照する.

docker-compose.ymlを元にコンテナを立ち上げたり止めたりする

  • docker-compose build
    • docker-compose.yml内の各サービスの各Dockerイメージを用意する.
  • docker-compose up -d
    • docker-compose.yml内の各サービスの各コンテナを起動する.
  • docker-compose ps
    • docker-compose.ymlに紐付いた,起動中のコンテナ一覧を表示する.
  • docker-compose stop
    • docker-compose.ymlに紐付いたすべてのコンテナを停止する.

関連記事 Related Posts

B!