この記事はCAMPHOR- Advent Calender 2015 22日目の記事です。
こんにちはkohey18です!(`・ω・´)ゞ
学生時代はCAMPHOR-の4期代表として頑張ってから上京して今に至ります(`・ω・´)ゞ
この一年、インフラエンジニアとして業務でDockerを触る機会がたくさんあり、その中でインフラエンジニアだけでなく、サーバサイドエンジニアもアプリのエンジニアももっとDockerを手元で触ってもらってDocker力があるとどんだけ楽だろうか。。。と思うことが多々あり、週末なり時間のあるときに試して欲しいDockerハンズオンをまとめておこうと思いました。
週末とかで試してみて、「あぁなるほど」と思って貰えればと思います。
対象者
- Docker初心者よりちょい上(一応初心者もわかるようにDockerfileの書き方から書いています)
- とりあえずDockerをローカルに入れているけど、何もしていない
- なんとなくDockerfileの書き方はわかる
Dockerとは
ここでは省略させてください!
様々な記事が上がっているかと思います!
書籍でいうと以下が良かったかも!
Dockerエキスパート養成読本[活用の基礎と実践ノウハウ満載!] (Software Design plus)
ハンズオンゴール
文字にすると
- docker-machineのポート8080のnginxコンテナにリクエストが来る(pオプションの理解)
- Sinatraのアプリケーションはnginxコンテナのproxy_pass経由でしかつながらない(linkオプションの理解)
- nginx, Sinatraのアプリケーションコンテナのログが全てfluentdのコンテナに送られる(logDriverの理解)
- fluentdのログは全てローカルPCに出力される(vオプションの理解)
とそれぞれ一応、Dockerの基本的〜応用的なことがローカルの環境で実現できるようにします。
環境
- docker-machine
- 構築はこちらを → docker-machineに変えた話
- docker
- version 1.9.1
- Mac OS X 10.10.5
docker-machineの設定(ポートフォワーディング等)は今回は省かせてもらいます。
構築手順
sinatra
- Sinatra
- Dockerfile
- app.rb
FROM ruby:2.2
MAINTAINER kohey
ADD app.rb app.rb
RUN gem install sinatra
EXPOSE 4567
CMD ["ruby", "app.rb"]
Dockerfileの書き方
初学者のためにDockerファイルの説明をすると、
Sinatraを動かすためにはもちろんruby
がコンテナ内で動いている必要がある。
今回、このコンテナ内のrubyの環境構築を楽にするためにrubyの2.2が動いているイメージを基にして、そこに上書きするようにしてみた。
先頭のFROM ruby:2.2
がそこを表している。
-
ADD
-
docker build
時にcurrent directory
のファイルをコンテナにぶち込む作業を行う。
-
-
RUN
-
docker build
時にコンテナに走らせたい処理を記載。
-
-
EXPOSE
- コンテナとして空けておくポートを記載。
require 'sinatra'
set :bind, '0.0.0.0'
get '/' do
"Hello World!"
end
こちらはHello World!
を出力するだけ
では、このSinatraアプリケーションのコンテナを動かしてみましょう!
$ docker build -t <your_name>/sinatra .
$ docker run --name sinatra -d <your_name>/sinatra
$ docker ps
kohey% docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
acfa7757f698 kohey/sinatra "ruby app.rb" 13 seconds ago Up 14 seconds 4567/tcp sinatra
これで問題ないです。
このSinatraのコンテナ、外からは見れない状態です。
docker-machine内部からはport4567
が空いているだけ。
上図のようにdocker-machine上にただ動いているだけ。
外から見れるようにするには、pオプション
を利用すればいいのですが、それはnginxのコンテナで試してみましょう!
nginx
- nginx
- Dockerfile
- nginx.conf
FROM ubuntu
MAINTAINER kohey
RUN apt-get update
RUN apt-get install -y nginx
# Remove the default Nginx configuration file
RUN rm -v /etc/nginx/nginx.conf
# Copy a configuration file from the current directory
ADD nginx.conf /etc/nginx/
# Expose ports
EXPOSE 80
# Set the default command to execute when creating a new container
CMD ["/usr/sbin/nginx", "-g", "daemon off;"]
worker_processes 5;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for" "$upstream_cache_status"';
access_log /var/log/nginx/access.log main;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://sinatra:4567; #Sinatraのアプリケーションにproxyする
}
}
}
動かしてみましょう!
$ docker build -t <your_name>/nginx .
$ docker run --name nginx -p 8080:80 --link sinatra:sinatra -d kohey/nginx
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ac12ce7600cc kohey/nginx "/usr/sbin/nginx -g '" 6 minutes ago Up 6 minutes 0.0.0.0:8080->80/tcp nginx
acfa7757f698 kohey/sinatra "ruby app.rb" 11 minutes ago Up 11 minutes 4567/tcp sinatra
pオプション
docker run -p docker-machineのポート番号:コンテナ内ポート番号
となる。
例えば、docker-machineのipが192.168.99.100
だとしたら、
docker-machineのipの調べ方はコチラ
192.168.99.100:8080
はport80
にフォワードされるから、すなわち、docker-machine内のnginxにリクエストが飛ぶこととなる。
かなり使うオプションなので抑えておいて欲しいです。
linkオプション
linkオプションを用いることでコンテナ間通信を可能にします。
すると、以下のようなところまで実現できました。
すると、外からnginxを通りproxy_passでsinatraのアプリケーションが見えるかと思います。
再掲: docker-machineのipの調べ方はコチラ
ここまで完全に理解できれば、最低限のDockerfileの書き方と最低限のオプションは理解できたかと思います。
応用編
Docker1.8からFluentd Log Driverが追加されました。
ローカルで試せるので少し試してみましょう!
fluentdのコンテナを立ち上げる
- fluentd
- Dockerfile
- td-agent.conf
FROM ubuntu
MAINTAINER kohey
RUN apt-get update && apt-get install -y --force-yes libssl0.9.8 curl
RUN curl -L http://toolbelt.treasuredata.com/sh/install-ubuntu-trusty-td-agent2.sh | sh && mkdir -p /var/log/td-agent
ENV GEM_HOME /opt/td-agent/embedded/lib/ruby/gems/2.1.0/
ENV GEM_PATH /opt/td-agent/embedded/lib/ruby/gems/2.1.0/
ENV PATH /opt/td-agent/embedded/bin/:$PATH
ADD ./config/td-agent.conf /etc/td-agent/td-agent.conf
RUN mkdir -p /var/log
EXPOSE 24224
CMD ["td-agent"]
- td-agent.conf
<source>
@type forward
@id forward_input
port 8888
</source>
<match **.**>
type copy
<store>
type file
path /var/log/td-agent/docker
</store>
<store>
type stdout
</store>
</match>
ログの入力をポート8888でHTTP通信で行うようにする。
動かしてみましょう!
$ docker build -t kohey/td-agent .
$ docker run --name td-agent -v /Users/kohey/Desktop/log/:/var/log/td-agent/docker -p 8888:8888 kohey/td-agent
vオプション
vオプションを使うとホストの任意のパスをコンテナの任意のパスにマウントすることができる
-v /Users/kohey/Desktop/log/:/var/log/td-agent
-v ホストの任意のパス:コンテナの任意のパス
こんな感じで書く
※※ 今回はdocker-machineが動いているVirtualBoxとローカルPCの共有フォルダを設定しているので、コンテナ
-> VirtualBox
-> ローカルMacPC
が実現可能である。
ここまで来ました!!!
気がつけば大作になったぞ!!!
logDriverを使う
では、先ほど動かしたSinatra
アプリケーションコンテナとnginx
コンテナをstopしましょう。
$ docker rm -f sinatra
$ docker rm -f nginx
そして、再度、ログドライバーオプションをつけたSinatra
アプリケーションコンテナとnginx
コンテナを動かしてみましょう!
$ docker run --name sinatra -d --log-driver=fluentd --log-opt=fluentd-address=192.168.99.100:8888 --log-opt fluentd-tag=docker.{{.Name}} kohey/sinatra
$ docker run --name nginx -p 8080:80 --link sinatra:sinatra --log-driver=fluentd --log-opt fluentd-address=192.168.99.100:8888 --log-opt fluentd-tag=docker.{{.Name}} kohey/nginx
--log-driver=fluentd --log-opt=fluentd-address=192.168.99.100:8888 --log-opt fluentd-tag=docker.{{.Name}}
- log-driver
- コンテナのログドライバーをfluentdにする(他のサポートもある)
- log-opt
- ログドライバーに必要な情報を与える
これでここまで来たかと思います!
ローカルのPCにログが出力されているはずなので見てみましょう!
下はローカルのPCに吐き出されたログをひたすらtail
している感じです!
fluentdのログもdocker.{{.Name}}
より、docker.sinatra
とかdocker.nginx
とかになっていると思います!
これでハンズオンのゴールが出来たかと思います!
まとめ
最低限のオプション等々を紹介した感じの大作になってしまった。
僕は初めて触った時に
「linkオプションを利用しただけでhttp://sinatra:4567
でproxy_pass通るのかよ!」
とか
「vオプションの使い方さえしっかりすればデータは永続化されそう!」
とか
「ログドライバーでコンテナのログが簡単に集まる・・・・!!便利じゃない??」
とかローカルの環境上でも感動する所は多々ありました。
実際、業務でもDocker使ってProduction運用していて、ログ周りとかデプロイ周りとか詰まりどころ多々あるけど、ちょっとずつ知見が溜まっている感じがします。
docker-machine上でちょっと凝ったことするときにこのハンズオンに出会ってもらえればなーとか思いました!
明日は、後輩のmikasakasaだよ!(`・ω・´)ゞ