読者です 読者をやめる 読者になる 読者になる

Djangoroidの奮闘記

python,django,angularJS1~三十路過ぎたプログラマーの奮闘記

Dockerを使ってみる 中編 ~Dockerfile~ djangoで使うことを想定

概要

とにかくdockerを使ってみる。今回は、dockerfile編。herokuで使うときも重要になってくる。

参考書籍

やってみたこと

Dockerfileについて

Dockerfileは、dockerのインフラ構成を記述したファイルのこと。

localでcontainerの設定するときは、Docker Containerを生成、Docker Container内で、apt-getなどのinstallを手動でやる必要がある。そうして出来上がったコンテナで構築した状態を元にDocker イメージを生成するという手順。

書籍より引用 ベースになるDockerイメージ Dockerコンテナ内で行った操作(コマンド) 環境変数などの設定 Docker コンテナ内で動作させておくデーモン実行

Dockerfileは、Docker場で動作させるコンテナの構成情報を記述しておくためのファイル。DockerはDockerfileを元にしてコンテナの元になるイメージを作成する。 docker build コマンドで、Docker imageを作成する。

Dockerfileの基本構成・作成

Docker コンテナをどのDockerイメージから生成するのか

FROM イメージ名

イメージ名を特定したい場合は、ダイジェストを指定する。

FROM [イメージ名]@[ダイジェスト]

# ダイジェストの確認方法
$ docker images --digests イメージ名

Dockerfileの作成者を記述する。

MAINTAINER [名前やメールアドレス]

DockerfileからDockerイメージを作成してみる

docker build -t [作成するイメージ名]:[タグ名] [Dockerfileの場所]

具体的には以下のような手順になる。

  • まず、Dockerfileを作成する、DockerfileにはFROM centos:centos7とか入れておく
  • docker build -t buildtest:1.0 /Users/test/sampledocker絶対パスにしてあるが、相対パスも可。

docker imageが出来上がった!

ちょっと混同しやすいと思ったのが、imageとcontainerの違い。これは注意しないと。

標準入力からのビルドも可能。 標準入力・出力については全く知らなかったけど、以下のサイトで何となく分かりました。

標準入力、標準出力、標準エラー出力、パイプとは ?

$ docker build - < Dockerfile

# ただ標準入力では、ADD命令などが使えないため、tarでまとめてから標準入力をする
$ docker build - < docker.tar.gz

Docker イメージのレイヤー構造

Dockerfileのサンプル。以下のような感じで、イメージは

FROM centos:latest <- 1つ目のイメージを作成

RUN yum install -y httpd <- 2つ目のイメージを作成

COPY index.html /var/www/html/ <- 3つ目のイメージを作成

CMD ["/usr/sbin/httpd", "-D", "FOREGROUND"] <- 4つ目のイメージを作成

コマンド/デーモンの実行

RUN [コマンド]

# shell形式
RUN yum -y install httpd
RUN echo これはshell形式

# exec形式
RUN ["/bin/bash", "-c", "yum -y install httpd"]
RUN ["echo", "これはexec形式"]
RUN ["/bin/bash", "-c", "echo 'こちらはexec形式'"]

# RUN命令を複数指定する場合(この場合、4つのイメージレイヤーが作られる
RUN yum -y install httpd
RUN yum -y install php
RUN yum -y install php-mbstring
RUN yum -y install php-pear

# RUN命令を1行で指定する場合(この場合、1つのイメージレイヤー
RUN yum -y install httpd php php-mbstring php-pear

# \ バックスラッシュで可読性をあげる
RUN yum -y install \
                     httpd \
                     php \
                     php-mbstring \
                     php-pear

デーモンの実行

  • RUN -> イメージを作成するために実行する
  • CMD -> イメージを元に生成したコンテナ内でコマンドを実行する
  • Dockerfileには、1つのCMDを記述することができる。複数指定した場合は、最後のコマンドのみ有効となる。
  • apacheを例にとると、RUN yum-y install httpdhttpdをinstallして、CMD /usr/sbin/httpd -D FOREGROUND でイメージを元に作成したコンテナ内で、常時Webサーバを起動させた状態にする。
  • exec形式の場合は、CMD ["/usr/sbin/httpd", "-D", "FOREGROUND"] となる。

Dockerfile例

FROM centos:centos7

RUN yum install -y httpd

CMD ["/usr/sbin/httpd", "-D", "FOREGROUND"]

docker buildで、imageを生成してみる。

docker build -t sample .

ただし、これはあくまでも、imageの生成で、コンテナの生成ではないので、注意!ここが自分的には混同しやすい。imageの生成とコンテナの生成・起動は全く別のステップとして認識する。

上記のイメージで、コンテナを生成・起動すると、自動でhttpdが起動するというイメージ!あくまでもDockerfileから生成されるのは、image!image生成後に、コンテナの生成・起動が必要。

docker run -d -p 80:80 sample

これで初めて、コンテナが起動して、sampleという名前のイメージが起動する。-p(port)は、コンテナのport80を、ホストの80に繋いでいるという意味。

ENTORYPOINT命令

ENTORYPOINT -> docker run コマンドでコンテナを起動した時に、実行されるコマンド (CMDとの使い方の違いはまだよくわかってない。)

# httpdの実行 shell
ENTORYPOINT /usr/sbin/httpd -D FOREGROUND

# httpdの実行 exec
ENTORYPOINT ["/usr/sbin/httpd", "-D", "FOREGROUND"]

ENTORYPOINTとCMDの違い

docker run コマンド(コンテナの起動・生成)の時の動作が違う。

  • CMD -> docker run で新たなコマンドを入れた場合は、そちらを優先して処理する(処理を上書きできる)
  • ENTORYPOINT -> docker run のコマンドよりも、ENTORYPOINTの処理を優先する。

例えば、

CMD ["/usr/sbin/httpd", "-D", "FOREGROUND"]
を記載したDockerfileのイメージを元にコンテナを起動して、

$ docker run -d -p 80:80 sample 

とコマンドを入力すると、httpdが起動する。

ただ、

$ docker run -d -p 81:80 sample /user/sbin/nginx -g "daemon off;"

というコマンドを打つと、nginxを優先して起動する。

これを、
ENTORYPOINT ["/usr/sbin/httpd", "-D", "FOREGROUND"]
に変更すると、

$ docker run -d -p 81:80 sample /user/sbin/nginx -g "daemon off;"

とうっても、httpdを起動するように指定しているので、nginxの起動は無効になる。

コンテナ実行時にコマンド引数を任意に指定したい時

Dockerfile

FROM centos:latest

ENTORYPOINT["top"]
CMD ["-d", "10"]

ターミナルで以下のように動作を確認できる。

$ docker run -it sample <- DockerfileのCMDで指定した10秒ごとに更新する

$ docker run -it sample -d 2 <- 2秒ごとに更新する

ビルド完了後に実行される命令(ONBUILD)

これはちょっとややこしいけど、イメージを重ねる時の肝になりそうな予感

Dockerfile1

FROM centos

ONBUILD RUN echo "Hello world"

Dockerfile1を元にイメージをビルドする。

docker build -t basesample .

この時点では、basesample image は、hello woldを表示しない。ONBUILDは、basesample imageを元に、buildした時に、発動する。

Dockerfile2

FROM basesample

このDockerfile2を元にイメージを作成した時に、echo "Hello world"が実行されるようになる。

docker build -t productsample .

productsample image をdocker runするとecho "Hello world"が実行される。

実際のONBUILDの使い方の例

まず、ベースイメージを作成する。

Dockerfile(baseimage)->webシステムの実行環境のイメージ

# Dcoker イメージの取得
FROM centos:latest

# Apache httpdのインストール
RUN ["yum", "-y", "install", "httpd"]

# Webコンテンツの配置
# このイメージを元に、buildする時に、website.tar をコンテナ内の/var/www/html/に追加するという指示
ONBUILD ADD website.tar /var/www/html/

# httpdの実行
CMD ["/usr/sbin/httpd", "-D", "FOREGROUND"]

このDockerfileの名前を、Dockerfile.baseという名前にする。 その場合、次のコマンドでイメージをビルドする。

# Dockerfile.baseを元に、web-baseという名前のイメージをビルド(作成)する。
$ docker build -t web-base -f Dockerfile.base .

web-baseを元に作成したコンテナでは、add website.tarは実行されない。このweb-baseを元に作成したイメージで起動したコンテナで、add website.tarが実行される。

website.tarを作成

とりあえず、仮のファイルとしてwebsite.tarを適当に作ってみる。

$ touch website.tar

Webサーバ用のイメージの作成

Dockerfileを作成

# Docker.baseを元にbuildしたweb-base imageを指定する
FROM web-base

Dockerfileとwebsite.tarは同じフォルダに入れておく

$ ls
Dockerfile  Dockerfile.base website.tar

Dockerfileを元にbuildしてみる。

$ docker build -t web-image .

無事buildできた!

webサーバ用コンテナの起動

# web-imageというイメージをもとに、ホストの80をコンテナの80をつなげてコンテナを起動・生成する。
$ docker run -d -p 80:80 web-image

多分、これでbaseと、アプリのデプロイの環境を分けることができる。

環境・ネットワークの設定

環境変数の設定(ENV命令)

2種類ある。

# ENV [キー名] [値] -> 複数のイメージが作られる
ENV myName "Djangoroid"
ENV myNumber = "1234567"

# ENV [キー名]=[値] -> 1つのイメージにまとめられる
ENV myName = "Djangoroid" \
        myNumber = "1234567" \

作業ディレクトリの指定(WORKDIR)

cd と似たようなコマンドになる。

WORKDIR /test
WORKDIR admin

# ENVで指定する場合(環境変数を使う場合は、$を先頭につける)
ENV DIRPATH /test
ENV DIRNAME admin
WORKDIR $DIRPATH/$DIRNAME
RUN ["pwd"]

ユーザーの指定

RUN ["adduser","test"]
RUN ["whoami"] <- root 
USER test
RUN ["whoami"] <- test

ラベルの指定(LABEL)

LABEL-> イメージにバージョン情報、コメント情報を持たせるとき

LABEL title="testimage"
LABEL version="2.0"

ポートの設定(EXPOSE)

# EXPOSE ホスト側のポート番号
EXPOSE 8080(<- ここはホスト側のポート)

ファイルシステムの設定

ファイル・ディレクトリの追加(ADD)

# ADD ホストPCのファイルパス Dockerイメージのファイルパス
ADD index.html /test_dir/ <-hostPCのindex.htmlを、Dockerイメージのtest_dirにコピーする。

# ADD ["ホストPCのファイルパス", "Dockerイメージのファイルパス"]

# 追加するファイルがリモートファイルURLの場合(ただし、ファイルはパーミッション600(ユーザーのみが読み書き可能)になるため注意)
ADD http://pythonskywalker.hatenablog.com/index.html /docker_dir/

# 認証が必要な場合は、RUN wget, curlを使う
# URLからファイルをダウンロードして、指定したファイル名を追加する
  • 絶対パス /path名/  どこにいるか関係なく、そのファイル・ディレクトリのfullpathを指定する。
  • 相対パス path名/ 今いるフォルダを起点にしてパスを指定する

ビルドで除外したいファイルには、.dockerignoreファイルを使う

$ cat .dockerignore
Dummyfile #Dummyfileという名前のファイルを書いておく。

Dockerfileに以下のように記載してimageをビルドして、.dockerignoreに記載されているので、dummyfileは、ADDされない。

FROM centos:latest

ADD dummyfile /tmp/dummyfile

ファイルのコピー(COPY)

ADD = リモートファイルのダウンロード、アーカイブの解凍などの機能がある COPY = 単純にコピーするだけ。そのため、イメージ内にファイルを配置したいだけの時は、COPY

Dockerfileの格納場所

Docker用のディレクトリを作成して、そこにDockerfileを置いてビルドするのがオススメ。不要なファイルをビルドしないように。

ボリュームのマウント(VOLUME)

web-container -> log-container を生成するときに、VOLUMEで、logの場所を指定することができる。

# web-image
FROM centos

# httpdのインストール
RUN yum install httpd

# log-image
FROM centos

# ボリュームの指定
VOLUME /var/log/httpd

実際に作ってみると、

Dockerfile(log-image用)

FROM centos:latest

RUN ["mkdir", "/var/log/httpd"]
VOLUME /var/log/httpd

log-imageをbuildしてみる。

$ docker build -t log-image .

log-imageをもとに、コンテナの起動・生成

$ docker run -it --name log-container log-image

webサーバ用のimageのDockerfileの作成

FROM centos:latest

RUN ["yum", "-y", "install", "httpd"]

CMD ["/usr/sbin/httpd", "-D", "FOREGROUND"]

webサーバ用のimageのビルド

$ docker build -t web-image .

webサーバ用コンテナの起動

$ docker run -d --name web-container \
> -p 80:80 \
> --volumes-from log-container web-image
  • --volumes-from [コンテナ名]で、指定する。

ログの確認

$ docker start -ia log-container
[root@ec2a2833b6c5 /]# ls -l /var/log/httpd
total 12
-rw-r--r-- 1 root root 4404 Oct 31 22:31 access_log
-rw-r--r-- 1 root root 1515 Oct 31 22:30 error_log